diff --git a/.gitattributes b/.gitattributes index 9c934ee9..773abcb8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ -# 2011 -src/BinaryKits.Zpl.Label.UnitTest/ZplData/*.txt text eol=lf \ No newline at end of file +* text=auto +src/BinaryKits.Zpl.Label.UnitTest/ZplData/*.txt text eol=lf +*.png binary diff --git a/.github/workflows/deploy_binarykits-zpl-viewer.yml b/.github/workflows/deploy_binarykits-zpl-viewer.yml index cb992818..605bfe4b 100644 --- a/.github/workflows/deploy_binarykits-zpl-viewer.yml +++ b/.github/workflows/deploy_binarykits-zpl-viewer.yml @@ -22,7 +22,7 @@ jobs: - name: Set up .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Build with dotnet working-directory: ./src/BinaryKits.Zpl.Viewer.WebApi diff --git a/.github/workflows/dotnet - test.yml b/.github/workflows/dotnet - test.yml index b6101dda..a481b552 100644 --- a/.github/workflows/dotnet - test.yml +++ b/.github/workflows/dotnet - test.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup .NET 6.0 + - name: Setup .NET 8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies working-directory: ./src run: dotnet restore @@ -33,10 +33,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup .NET 6.0 + - name: Setup .NET 8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies working-directory: ./src run: dotnet restore diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index d3ed0db9..cfd42964 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup .NET 6.0 + - name: Setup .NET 8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies working-directory: ./src run: dotnet restore @@ -33,10 +33,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup .NET 6.0 + - name: Setup .NET 8.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies working-directory: ./src run: dotnet restore diff --git a/README.md b/README.md index 8f1dc98d..f305ca9b 100644 --- a/README.md +++ b/README.md @@ -307,3 +307,4 @@ foreach (var labelInfo in analyzeInfo.LabelInfos) | JavaScript | [JSZPL](https://github.com/DanieLeeuwner/JSZPL) | | .NET | [sharpzebra](https://github.com/rkone/sharpzebra) | | .NET | [PDFtoZPL](https://github.com/sungaila/PDFtoZPL) | +| .NET | [ZPL2PDF](https://github.com/brunoleocam/ZPL2PDF) | diff --git a/src/.editorconfig b/src/.editorconfig index 1ae3ce87..1ca560aa 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -28,6 +28,8 @@ csharp_new_line_before_else = true csharp_new_line_before_members_in_object_initializers = true #require braces to be on a new line for methods, object_collection_array_initializers, control_blocks, and types (also known as "Allman" style) csharp_new_line_before_open_brace = methods, object_collection_array_initializers, control_blocks, types +dotnet_style_allow_multiple_blank_lines_experimental = false:suggestion +dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion #Formatting - organize using options @@ -81,15 +83,16 @@ dotnet_style_predefined_type_for_member_access = true:suggestion #prefer objects to be initialized using object initializers when possible dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = when_types_exactly_match #Style - implicit and explicit types #prefer var over explicit type in all cases, unless overridden by another code style rule -csharp_style_var_elsewhere = true:suggestion +csharp_style_var_elsewhere = false:warning #prefer var is used to declare variables with built-in system types such as int -csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_for_built_in_types = false:warning #prefer var when the type is already mentioned on the right-hand side of a declaration expression -csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_when_type_is_apparent = false:warning #Style - language keyword and framework type options @@ -104,7 +107,7 @@ dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggest #Style - Modifier preferences #when this rule is set to a list of modifiers, prefer the specified ordering. -csharp_preferred_modifier_order = public,private,protected,override,readonly,static,abstract:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,override,static,abstract,readonly:suggestion #Style - Pattern matching @@ -113,9 +116,11 @@ csharp_style_pattern_matching_over_as_with_null_check = true:suggestion #Style - qualification options -#prefer fields not to be prefaced with this. or Me. in Visual Basic -dotnet_style_qualification_for_field = false:suggestion +#prefer fields to be prefaced with this. or Me. in Visual Basic +dotnet_style_qualification_for_field = true:suggestion #prefer methods to be prefaced with this. in C# or Me. in Visual Basic dotnet_style_qualification_for_method = true:suggestion #prefer properties to be prefaced with this. in C# or Me. in Visual Basic dotnet_style_qualification_for_property = true:suggestion + +csharp_style_prefer_primary_constructors = false:suggestion \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs index f6a33f9b..5a367fc4 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs @@ -21,7 +21,7 @@ public void Barcode39() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^XA\n^LH0,0\n^CI28\n\n^FO100,100\n^BY2,3\n^B3N,N,100,Y,N\n^FD123ABC^FS\n^XZ", output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,100\n^BY2,3\n^B3N,N,100,Y,N\n^FD123ABC^FS\n^XZ", output); } [TestMethod] @@ -37,7 +37,7 @@ public void Barcode93() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^XA\n^LH0,0\n^CI28\n\n^FO100,300\n^BY2,3\n^BAN,100,Y,N,N\n^FD123ABC^FS\n^XZ", output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,300\n^BY2,3\n^BAN,100,Y,N,N\n^FD123ABC^FS\n^XZ", output); } [TestMethod] @@ -53,7 +53,7 @@ public void Barcode128() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^XA\n^LH0,0\n^CI28\n\n^FO100,300\n^BY2,3\n^BCN,100,Y,N\n^FD123ABC^FS\n^XZ", output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,300\n^BY2,3\n^BCN,100,Y,N\n^FD123ABC^FS\n^XZ", output); } [TestMethod] @@ -69,7 +69,39 @@ public void BarcodeEan13() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^XA\n^LH0,0\n^CI28\n\n^FO100,300\n^BY2,3\n^BEN,100,Y,N\n^FD123456^FS\n^XZ", output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,300\n^BY2,3\n^BEN,100,Y,N\n^FD123456^FS\n^XZ", output); + } + + [TestMethod] + public void DataMatrixDefault() + { + var elements = new List + { + new ZplDataMatrix("123ABC", 100, 300) + }; + + var renderEngine = new ZplEngine(elements); + var output = renderEngine.ToZplString(new ZplRenderOptions { AddEmptyLineBeforeElementStart = true }); + + Debug.WriteLine(output); + Assert.IsNotNull(output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,300\n^BXN,100,0\n^FD123ABC^FS\n^XZ", output); + } + + [TestMethod] + public void DataMatrix200() + { + var elements = new List + { + new ZplDataMatrix("123ABC", 100, 300, qualityLevel: QualityLevel.ECC200) + }; + + var renderEngine = new ZplEngine(elements); + var output = renderEngine.ToZplString(new ZplRenderOptions { AddEmptyLineBeforeElementStart = true }); + + Debug.WriteLine(output); + Assert.IsNotNull(output); + Assert.AreEqual("^XA\n^LH0,0\n\n^FO100,300\n^BXN,100,200\n^FD123ABC^FS\n^XZ", output); } } } diff --git a/src/BinaryKits.Zpl.Label.UnitTest/BinaryKits.Zpl.Label.UnitTest.csproj b/src/BinaryKits.Zpl.Label.UnitTest/BinaryKits.Zpl.Label.UnitTest.csproj index 42897ddc..50b7a077 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/BinaryKits.Zpl.Label.UnitTest.csproj +++ b/src/BinaryKits.Zpl.Label.UnitTest/BinaryKits.Zpl.Label.UnitTest.csproj @@ -1,19 +1,15 @@  - net6.0 - + net8.0 + net472;net8.0 false - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + @@ -27,6 +23,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/BinaryKits.Zpl.Label.UnitTest/DownloadTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/DownloadTest.cs index 32efeb55..defaa96d 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/DownloadTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/DownloadTest.cs @@ -41,6 +41,7 @@ public void DownloadGraphicsACS() [TestMethod] [DeploymentItem(@"ZplData/Zpl.png")] [DeploymentItem(@"ZplData/DownloadGraphicsZ64.txt")] + [DeploymentItem(@"ZplData/DownloadGraphicsZ64_net472.txt")] public void DownloadGraphicsZ64() { var imageData = File.ReadAllBytes("Zpl.png"); @@ -63,7 +64,11 @@ public void DownloadGraphicsZ64() Debug.WriteLine(output); Assert.IsNotNull(output); +#if NET5_0_OR_GREATER var zplData = File.ReadAllText("DownloadGraphicsZ64.txt"); +#else + var zplData = File.ReadAllText("DownloadGraphicsZ64_net472.txt"); +#endif Assert.AreEqual(zplData, output); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Label.UnitTest/EngineTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/EngineTest.cs index 2033628a..064ec672 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/EngineTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/EngineTest.cs @@ -54,7 +54,7 @@ public void ChangeDPI() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^XA\n^LH0,0\n^CI28\n^FO591,1034\n^GB147,147,7,B,0^FS\n^XZ", output); + Assert.AreEqual("^XA\n^LH0,0\n^FO591,1034\n^GB147,147,7,B,0^FS\n^XZ", output); } [TestMethod] @@ -102,9 +102,9 @@ public void TextFieldVariations() var elements = new List(); //Specail character is repalced with space - elements.Add(new ZplTextField(sampleText, 10, 10, font, useHexadecimalIndicator: false)); + elements.Add(new ZplTextField(sampleText, 10, 10, font, hexadecimalIndicator: null)); //Specail character is using Hex value ^FH - elements.Add(new ZplTextField(sampleText, 10, 50, font, useHexadecimalIndicator: true)); + elements.Add(new ZplTextField(sampleText, 10, 50, font, hexadecimalIndicator: '_')); //Only the first line is displayed elements.Add(new ZplSingleLineFieldBlock(sampleText, 10, 150, 500, font)); //Max 2 lines, text exceeding the maximum number of lines overwrites the last line. @@ -132,7 +132,41 @@ public void WithoutAutoElements() Debug.WriteLine(output); Assert.IsNotNull(output); - Assert.AreEqual("^CI28\n^FX\n//A important field\n^A0N,30,30\n^FO50,100\n^FH^FDPure element zpl only^FS", output); + Assert.AreEqual("^FX\n//A important field\n^A0N,30,30\n^FO50,100\n^FDPure element zpl only^FS", output); + } + + [TestMethod] + public void ChangeInternationalFont() + { + var elements = new List() { + new ZplChangeInternationalFont(InternationalFont.ZCP1252), + new ZplTextField("Straße", 10, 10, ZplConstants.Font.Default, hexadecimalIndicator: '_'), + }; + + var renderEngine = new ZplEngine(elements); + var output = renderEngine.ToZplString(new ZplRenderOptions()); + + Debug.WriteLine(output); + Assert.IsNotNull(output); + //TODO: escape non-ascii characters according to current charset if hexIndicator is given + Assert.AreEqual("^XA\n^LH0,0\n^CI27\n^A0N,30,30\n^FO10,10\n^FH^FDStraße^FS\n^XZ", output); + } + + [TestMethod] + public void FieldTypesetDefaultPosition() + { + var elements = new List() { + new ZplTextField("ACME ", 10, 200, new ZplFont(30, 20, "0"), bottomToTop: true), + new ZplTextField("Summer ", 0, 0, new ZplFont(30, 20, "0"), bottomToTop: true, useDefaultPosition: true), + new ZplTextField("Clearance ", 0, 0, new ZplFont(60, 50, "0"), bottomToTop: true, useDefaultPosition: true), + new ZplTextField("Sale ", 0, 0, new ZplFont(120, 100, "0"), bottomToTop: true, useDefaultPosition: true) + }; + + var renderEngine = new ZplEngine(elements); + var output = renderEngine.ToZplString(new ZplRenderOptions()); + + Debug.WriteLine(output); + Assert.AreEqual("^XA\n^LH0,0\n^A0N,20,30\n^FT10,200\n^FDACME ^FS\n^A0N,20,30\n^FT\n^FDSummer ^FS\n^A0N,50,60\n^FT\n^FDClearance ^FS\n^A0N,100,120\n^FT\n^FDSale ^FS\n^XZ", output); } } } diff --git a/src/BinaryKits.Zpl.Label.UnitTest/FieldNumberTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/FieldNumberTest.cs index 82ccaefc..8c7cf3dd 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/FieldNumberTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/FieldNumberTest.cs @@ -14,14 +14,14 @@ public void SingleElement() var output = new ZplFieldNumber(100, textField).ToZplString(); Assert.IsNotNull(output); - Assert.AreEqual("^A0N,30,30\n^FO50,100\n^FH\n^FN100^FS", output); + Assert.AreEqual("^A0N,30,30\n^FO50,100\n^FD^FS\n^FN100^FS", output); } [TestMethod] public void WrongTypeElement() { var data = new ZplReferenceGrid(); - Assert.ThrowsException(() => new ZplFieldNumber(100, data).ToZplString()); + Assert.Throws(() => new ZplFieldNumber(100, data).ToZplString()); } } -} \ No newline at end of file +} diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZebraZ64CompressionHelperTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/ZebraZ64CompressionHelperTest.cs index 92b742e2..33585d10 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/ZebraZ64CompressionHelperTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZebraZ64CompressionHelperTest.cs @@ -8,6 +8,16 @@ namespace BinaryKits.Zpl.Label.UnitTest [TestClass] public class ZebraZ64CompressionHelperTest { + [TestMethod] + public void CompressUncompress_Flow_Successful() + { + var originalData = "FFFFFFFFFFFFFFFFFFFF8000FFFF0000FFFF00018000FFFF0000FFFF00018000FFFF0000FFFF0001FFFF0000FFFF0000FFFFFFFF0000FFFF0000FFFFFFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF"; + + string compressed = ZebraZ64CompressionHelper.Compress(originalData); + string uncompressed = ZebraZ64CompressionHelper.Uncompress(compressed).ToHexFromBytes(); + Assert.AreEqual(originalData, uncompressed); + } +#if NET5_0_OR_GREATER [TestMethod] public void Compress_ValidData1_Successful() { @@ -19,16 +29,6 @@ public void Compress_ValidData1_Successful() //^XGR:SAMPLE.GRF,1,1^FS //^XZ } - [TestMethod] - public void CompressUncompress_Flow_Successful() - { - var originalData = "FFFFFFFFFFFFFFFFFFFF8000FFFF0000FFFF00018000FFFF0000FFFF00018000FFFF0000FFFF0001FFFF0000FFFF0000FFFFFFFF0000FFFF0000FFFFFFFF0000FFFF0000FFFFFFFFFFFFFFFFFFFFFFFF"; - - string compressed = ZebraZ64CompressionHelper.Compress(originalData); - string uncompressed = ZebraZ64CompressionHelper.Uncompress(compressed).ToHexFromBytes(); - Assert.AreEqual(originalData, uncompressed); - } -#if NET5_0_OR_GREATER [TestMethod] public void DeflateNetStandardSameAsNetCore_Optimal_Successful() { diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsACS.txt b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsACS.txt index 1e7559d4..5961bac5 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsACS.txt +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsACS.txt @@ -1,6 +1,5 @@ ^XA ^LH0,0 -^CI28 ^FO0,0 ^GB100,100,4,B,0^FS diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsB64.txt b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsB64.txt index b3c7f2e3..9fc468b5 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsB64.txt +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsB64.txt @@ -1,6 +1,5 @@ ^XA ^LH0,0 -^CI28 ^FO0,0 ^GB100,100,4,B,0^FS diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64.txt b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64.txt index b28ad728..7be9909f 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64.txt +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64.txt @@ -1,6 +1,5 @@ ^XA ^LH0,0 -^CI28 ^FO0,0 ^GB100,100,4,B,0^FS diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64_net472.txt b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64_net472.txt new file mode 100644 index 00000000..ffa40dcb --- /dev/null +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadGraphicsZ64_net472.txt @@ -0,0 +1,12 @@ +^XA +^LH0,0 + +^FO0,0 +^GB100,100,4,B,0^FS + +~DGR:SAMPLE.GRF,1190,17, +:Z64:eJzV0z0OwyAMBeBHxMBWjuBUHTr2BuFoHK3H6hRq07T8DPaaIkGeviV+QQH+Zm2llPw5XhWId37IQeELDvcZbiMsuM6wjuBBeYY0QADRDLHBVp4RdNl/ACSGsHSQyQCHZABHA7yDAZzHSSt03wPRWyBPHbi9AdxeB2nPk/LtDxCO1x3tdZD2Okh7HaS9Dm3ImvoaNZ0H2s9UE0673ohsTn0=:e802 + +^FO100,100 +^XGR:SAMPLE.GRF,1,1^FS +^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadObject.txt b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadObject.txt index 768be995..c1070397 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadObject.txt +++ b/src/BinaryKits.Zpl.Label.UnitTest/ZplData/DownloadObject.txt @@ -1,6 +1,5 @@ ^XA ^LH0,0 -^CI28 ^FO0,0 ^GB150,150,6,B,0^FS diff --git a/src/BinaryKits.Zpl.Label/BinaryKits.Zpl.Label.csproj b/src/BinaryKits.Zpl.Label/BinaryKits.Zpl.Label.csproj index 379fc168..4245dfd0 100644 --- a/src/BinaryKits.Zpl.Label/BinaryKits.Zpl.Label.csproj +++ b/src/BinaryKits.Zpl.Label/BinaryKits.Zpl.Label.csproj @@ -1,10 +1,10 @@  - net472;netstandard2.0;net6.0 + net472;netstandard2.0;net8.0 This package allows you to simply and reliably prepare labels complying with the Zebra programming language, using predefined class/typing. It also supports you with image conversion. Binary Kits Pte. Ltd. - 3.2.1 + 3.3.0 Binary Kits Pte. Ltd. Zebra ZPL ZPL2 Printer Label @@ -21,11 +21,18 @@ snupkg - - - 2.1.8 - - + + + + + + + + + + + + diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplAztecBarcode.cs b/src/BinaryKits.Zpl.Label/Elements/ZplAztecBarcode.cs new file mode 100644 index 00000000..71e8a1c6 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplAztecBarcode.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Text; + +namespace BinaryKits.Zpl.Label.Elements +{ + public class ZplAztecBarcode : ZplFieldDataElementBase + { + public int MagnificationFactor { get; protected set; } + public bool ExtendedChannel { get; protected set; } + public int ErrorControl { get; protected set; } + public bool MenuSymbol { get; protected set; } + public int SymbolCount { get; protected set; } + public string IdField { get; protected set; } + + /// + /// Aztec Bar Code + /// + /// + /// + /// + /// + /// extended channel interpretation code indicator + /// error control and symbol size/type indicator + /// menu symbol indicator + /// number of symbols for structured append + /// optional ID field for structured append + /// + /// + /// + /// + public ZplAztecBarcode( + string content, + int positionX, + int positionY, + int magnificationFactor = 2, + bool extendedChannel = false, + int errorControl = 0, + bool menuSymbol = false, + int symbolCount = 1, + string idField = null, + FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, positionX, positionY, fieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition) + { + this.MagnificationFactor = magnificationFactor; + this.ExtendedChannel = extendedChannel; + this.ErrorControl = errorControl; + this.SymbolCount = symbolCount; + this.IdField = idField; + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + var result = new List(); + result.AddRange(RenderPosition(context)); + result.Add($"^BO{RenderFieldOrientation(this.FieldOrientation)},{this.MagnificationFactor},{RenderBoolean(this.ExtendedChannel)}," + + $"{this.ErrorControl},{RenderBoolean(this.MenuSymbol)},{this.SymbolCount},{this.IdField}"); + result.Add(RenderFieldDataSection()); + + return result; + } + } +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode.cs index 6600f706..851817f7 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode.cs @@ -1,7 +1,20 @@ -namespace BinaryKits.Zpl.Label.Elements +using System.Text; + +using static System.Net.Mime.MediaTypeNames; + +namespace BinaryKits.Zpl.Label.Elements { - public abstract class ZplBarcode : ZplPositionedElementBase, IFormatElement + public abstract class ZplBarcode : ZplFieldDataElementBase { + /// + /// Module width (in dots) + /// + public int ModuleWidth { get; protected set; } + public double WideBarToNarrowBarWidthRatio { get; protected set; } + public int Height { get; protected set; } + public bool PrintInterpretationLine { get; protected set; } + public bool PrintInterpretationLineAboveCode { get; protected set; } + public ZplBarcode( string content, int positionX, @@ -10,47 +23,28 @@ public ZplBarcode( int moduleWidth, double wideBarToNarrowBarWidthRatio, FieldOrientation fieldOrientation, + char? hexadecimalIndicator, bool printInterpretationLine, bool printInterpretationLineAboveCode, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + bool bottomToTop, + bool useDefaultPosition) + : base(content, positionX, positionY, fieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition) { - Content = content; Height = height; ModuleWidth = moduleWidth; WideBarToNarrowBarWidthRatio = wideBarToNarrowBarWidthRatio; - FieldOrientation = fieldOrientation; PrintInterpretationLine = printInterpretationLine; PrintInterpretationLineAboveCode = printInterpretationLineAboveCode; } - /// - /// Module width (in dots) - /// - public int ModuleWidth { get; protected set; } - public double WideBarToNarrowBarWidthRatio { get; protected set; } - - public int Height { get; protected set; } - - public FieldOrientation FieldOrientation { get; protected set; } - - public string Content { get; protected set; } - public bool PrintInterpretationLine { get; protected set; } - public bool PrintInterpretationLineAboveCode { get; protected set; } - - public string RenderPrintInterpretationLine() - { - return PrintInterpretationLine ? "Y" : "N"; - } - - public string RenderPrintInterpretationLineAboveCode() + protected string RenderPrintInterpretationLine() { - return PrintInterpretationLineAboveCode ? "Y" : "N"; + return RenderBoolean(PrintInterpretationLine); } - protected string RenderFieldOrientation() + protected string RenderPrintInterpretationLineAboveCode() { - return RenderFieldOrientation(FieldOrientation); + return RenderBoolean(PrintInterpretationLineAboveCode); } protected string RenderModuleWidth() @@ -58,23 +52,5 @@ protected string RenderModuleWidth() return $"^BY{ModuleWidth},{WideBarToNarrowBarWidthRatio}"; } - protected bool IsDigitsOnly(string text) - { - foreach (char c in text) - { - if (c < '0' || c > '9') - { - return false; - } - } - - return true; - } - - /// - public void SetTemplateContent(string content) - { - Content = content; - } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode128.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode128.cs index 1b0769d4..b337daaf 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode128.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode128.cs @@ -7,7 +7,6 @@ namespace BinaryKits.Zpl.Label.Elements /// public class ZplBarcode128 : ZplBarcode { - public string Mode { get; set; } /// @@ -20,9 +19,11 @@ public class ZplBarcode128 : ZplBarcode /// /// /// + /// /// /// /// + /// /// public ZplBarcode128( string content, @@ -32,9 +33,11 @@ public ZplBarcode128( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, bool bottomToTop = false, + bool useDefaultPosition = false, string mode = "N") : base(content, positionX, @@ -43,9 +46,11 @@ public ZplBarcode128( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { this.Mode = mode; } @@ -62,7 +67,7 @@ public override IEnumerable Render(ZplRenderOptions context) result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); result.Add($"^BC{RenderFieldOrientation()},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()}"); - result.Add($"^FD{Content}^FS"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode39.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode39.cs index f0fb11bb..956b1517 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode39.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode39.cs @@ -19,10 +19,12 @@ public class ZplBarcode39 : ZplBarcode /// /// /// + /// /// /// /// /// + /// public ZplBarcode39( string content, int positionX, @@ -31,10 +33,12 @@ public ZplBarcode39( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, bool mod43CheckDigit = false, - bool bottomToTop = false) + bool bottomToTop = false, + bool useDefaultPosition = false) : base(content, positionX, positionY, @@ -42,9 +46,11 @@ public ZplBarcode39( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { Mod43CheckDigit = mod43CheckDigit; } @@ -58,8 +64,8 @@ public override IEnumerable Render(ZplRenderOptions context) var result = new List(); result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); - result.Add($"^B3{RenderFieldOrientation()},{(Mod43CheckDigit ? "Y" : "N")},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()}"); - result.Add($"^FD{Content}^FS"); + result.Add($"^B3{RenderFieldOrientation()},{RenderBoolean(Mod43CheckDigit)},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()}"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs index 9aae382d..1354b207 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs @@ -19,10 +19,12 @@ public class ZplBarcode93 : ZplBarcode /// /// /// + /// /// /// - /// /// + /// + /// public ZplBarcode93( string content, int positionX, @@ -31,10 +33,12 @@ public ZplBarcode93( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, bool checkDigit = false, - bool bottomToTop = false) + bool bottomToTop = false, + bool useDefaultPosition = false) : base(content, positionX, positionY, @@ -42,9 +46,11 @@ public ZplBarcode93( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { this.CheckDigit = checkDigit; } @@ -60,8 +66,8 @@ public override IEnumerable Render(ZplRenderOptions context) var result = new List(); result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); - result.Add($"^BA{RenderFieldOrientation()},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{(CheckDigit ? "Y" : "N")}"); - result.Add($"^FD{Content}^FS"); + result.Add($"^BA{RenderFieldOrientation()},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{RenderBoolean(CheckDigit)}"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeAnsiCodabar.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeAnsiCodabar.cs index 137fae8b..e1031dc3 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeAnsiCodabar.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeAnsiCodabar.cs @@ -25,10 +25,12 @@ public class ZplBarcodeAnsiCodabar : ZplBarcode /// /// /// + /// /// /// /// /// + /// public ZplBarcodeAnsiCodabar( string content, char startCharacter, @@ -39,10 +41,12 @@ public ZplBarcodeAnsiCodabar( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, bool checkDigit = false, - bool bottomToTop = false) + bool bottomToTop = false, + bool useDefaultPosition = false) : base(content, positionX, positionY, @@ -50,9 +54,11 @@ public ZplBarcodeAnsiCodabar( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { if (!IsValidCharacter(startCharacter)) { @@ -84,8 +90,8 @@ public override IEnumerable Render(ZplRenderOptions context) var result = new List(); result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); - result.Add($"^BK{RenderFieldOrientation()},{(CheckDigit ? "Y" : "N")},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{StartCharacter},{StopCharacter}"); - result.Add($"^FD{Content}^FS"); + result.Add($"^BK{RenderFieldOrientation()},{RenderBoolean(CheckDigit)},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{StartCharacter},{StopCharacter}"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeEan13.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeEan13.cs index efa85b83..d934038f 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeEan13.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeEan13.cs @@ -18,9 +18,11 @@ public class ZplBarcodeEan13 : ZplBarcode /// /// /// + /// /// /// /// + /// public ZplBarcodeEan13( string content, int positionX, @@ -29,9 +31,11 @@ public ZplBarcodeEan13( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, - bool bottomToTop = false) + bool bottomToTop = false, + bool useDefaultPosition = false) : base(content, positionX, positionY, @@ -39,14 +43,12 @@ public ZplBarcodeEan13( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { - if (!IsDigitsOnly(content)) - { - throw new ArgumentException("EAN-13 Barcode allow only digits", nameof(content)); - } } /// @@ -56,7 +58,7 @@ public override IEnumerable Render(ZplRenderOptions context) result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); result.Add($"^BE{RenderFieldOrientation()},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()}"); - result.Add($"^FD{Content}^FS"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeInterleaved2of5.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeInterleaved2of5.cs index 59a3d943..aae1d10f 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeInterleaved2of5.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeInterleaved2of5.cs @@ -20,10 +20,12 @@ public class ZplBarcodeInterleaved2of5 : ZplBarcode /// /// /// + /// /// /// /// /// + /// public ZplBarcodeInterleaved2of5( string content, int positionX, @@ -32,10 +34,12 @@ public ZplBarcodeInterleaved2of5( int moduleWidth = 2, double wideBarToNarrowBarWidthRatio = 3, FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, bool printInterpretationLine = true, bool printInterpretationLineAboveCode = false, bool mod10CheckDigit = false, - bool bottomToTop = false) + bool bottomToTop = false, + bool useDefaultPosition = false) : base(content, positionX, positionY, @@ -43,15 +47,12 @@ public ZplBarcodeInterleaved2of5( moduleWidth, wideBarToNarrowBarWidthRatio, fieldOrientation, + hexadecimalIndicator, printInterpretationLine, printInterpretationLineAboveCode, - bottomToTop) + bottomToTop, + useDefaultPosition) { - if (!IsDigitsOnly(content)) - { - throw new ArgumentException("Interleaved 2 of 5 Barcode allow only digits", nameof(content)); - } - Mod10CheckDigit = mod10CheckDigit; } @@ -62,7 +63,7 @@ public override IEnumerable Render(ZplRenderOptions context) result.AddRange(RenderPosition(context)); result.Add(RenderModuleWidth()); result.Add($"^B2{RenderFieldOrientation()},{context.Scale(Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{(Mod10CheckDigit ? "Y" : "N")}"); - result.Add($"^FD{Content}^FS"); + result.Add(RenderFieldDataSection()); return result; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcA.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcA.cs new file mode 100644 index 00000000..eb39f9b5 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcA.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace BinaryKits.Zpl.Label.Elements +{ + /// + /// UPC-A Barcode + /// + public class ZplBarcodeUpcA : ZplBarcode + { + public bool PrintCheckDigit { get; private set; } + + /// + /// UPC-A Barcode + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public ZplBarcodeUpcA( + string content, + int positionX, + int positionY, + int height = 100, + int moduleWidth = 2, + double wideBarToNarrowBarWidthRatio = 3, + FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, + bool printInterpretationLine = true, + bool printInterpretationLineAboveCode = false, + bool printCheckDigit = true, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, + positionX, + positionY, + height, + moduleWidth, + wideBarToNarrowBarWidthRatio, + fieldOrientation, + hexadecimalIndicator, + printInterpretationLine, + printInterpretationLineAboveCode, + bottomToTop, + useDefaultPosition) + { + this.PrintCheckDigit = printCheckDigit; + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + List result = new List(); + result.AddRange(RenderPosition(context)); + result.Add(RenderModuleWidth()); + result.Add($"^BU{RenderFieldOrientation()},{context.Scale(this.Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{RenderBoolean(this.PrintCheckDigit)}"); + result.Add(RenderFieldDataSection()); + + return result; + } + } +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcE.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcE.cs new file mode 100644 index 00000000..411fc8a3 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcE.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace BinaryKits.Zpl.Label.Elements +{ + /// + /// UPC-E Barcode + /// + public class ZplBarcodeUpcE : ZplBarcode + { + public bool PrintCheckDigit { get; private set; } + + /// + /// UPC-A Barcode + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public ZplBarcodeUpcE( + string content, + int positionX, + int positionY, + int height = 100, + int moduleWidth = 2, + double wideBarToNarrowBarWidthRatio = 3, + FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, + bool printInterpretationLine = true, + bool printInterpretationLineAboveCode = false, + bool printCheckDigit = true, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, + positionX, + positionY, + height, + moduleWidth, + wideBarToNarrowBarWidthRatio, + fieldOrientation, + hexadecimalIndicator, + printInterpretationLine, + printInterpretationLineAboveCode, + bottomToTop, + useDefaultPosition) + { + this.PrintCheckDigit = printCheckDigit; + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + List result = new List(); + result.AddRange(RenderPosition(context)); + result.Add(RenderModuleWidth()); + result.Add($"^B9{RenderFieldOrientation()},{context.Scale(this.Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()},{RenderBoolean(this.PrintCheckDigit)}"); + result.Add(RenderFieldDataSection()); + + return result; + } + } +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcExtension.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcExtension.cs new file mode 100644 index 00000000..d9226cd8 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcodeUpcExtension.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; + +namespace BinaryKits.Zpl.Label.Elements +{ + /// + /// UPC-E Barcode + /// + public class ZplBarcodeUpcExtension : ZplBarcode + { + /// + /// UPC Extension Barcode + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public ZplBarcodeUpcExtension( + string content, + int positionX, + int positionY, + int height = 100, + int moduleWidth = 2, + double wideBarToNarrowBarWidthRatio = 3, + FieldOrientation fieldOrientation = FieldOrientation.Normal, + char? hexadecimalIndicator = null, + bool printInterpretationLine = true, + bool printInterpretationLineAboveCode = false, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, + positionX, + positionY, + height, + moduleWidth, + wideBarToNarrowBarWidthRatio, + fieldOrientation, + hexadecimalIndicator, + printInterpretationLine, + printInterpretationLineAboveCode, + bottomToTop, + useDefaultPosition) + { + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + List result = new List(); + result.AddRange(RenderPosition(context)); + result.Add(RenderModuleWidth()); + result.Add($"^BS{RenderFieldOrientation()},{context.Scale(this.Height)},{RenderPrintInterpretationLine()},{RenderPrintInterpretationLineAboveCode()}"); + result.Add(RenderFieldDataSection()); + + return result; + } + } +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplChangeInternationalFont.cs b/src/BinaryKits.Zpl.Label/Elements/ZplChangeInternationalFont.cs new file mode 100644 index 00000000..1842ca52 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplChangeInternationalFont.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace BinaryKits.Zpl.Label.Elements +{ + /// + /// ^CI - Change International Font/Encoding + /// + public class ZplChangeInternationalFont : ZplElementBase + { + public InternationalFont InternationalFont { get; private set; } + + public ZplChangeInternationalFont(InternationalFont internationalFont) + { + this.InternationalFont = internationalFont; + } + + public override IEnumerable Render(ZplRenderOptions context) + { + return new[] { $"^CI{(int)this.InternationalFont}" }; + } + } + +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplDataMatrix.cs b/src/BinaryKits.Zpl.Label/Elements/ZplDataMatrix.cs index 85376eb1..ec758672 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplDataMatrix.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplDataMatrix.cs @@ -1,12 +1,17 @@ using System.Collections.Generic; +using System.Text; namespace BinaryKits.Zpl.Label.Elements { /// /// Data Matrix Bar Code, ^BXo,h,s,c,r,f,g,a /// - public class ZplDataMatrix : ZplPositionedElementBase, IFormatElement + public class ZplDataMatrix : ZplFieldDataElementBase { + public int Height { get; protected set; } + + public QualityLevel QualityLevel { get; protected set; } + /// /// Data Matrix Bar Code /// @@ -14,32 +19,30 @@ public class ZplDataMatrix : ZplPositionedElementBase, IFormatElement /// /// /// + /// /// + /// /// + /// public ZplDataMatrix( string content, int positionX, int positionY, int height = 100, + QualityLevel qualityLevel = QualityLevel.ECC0, FieldOrientation fieldOrientation = FieldOrientation.Normal, - bool bottomToTop = false - ) - : base(positionX, positionY, bottomToTop) + char? hexadecimalIndicator = null, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, positionX, positionY, fieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition) { - Content = content; - FieldOrientation = fieldOrientation; Height = height; + QualityLevel = qualityLevel; } - public int Height { get; protected set; } - - public FieldOrientation FieldOrientation { get; protected set; } - - public string Content { get; protected set; } - - protected string RenderFieldOrientation() + protected string RenderQualityLevel() { - return RenderFieldOrientation(FieldOrientation); + return RenderQualityLevel(QualityLevel); } /// @@ -50,16 +53,11 @@ public override IEnumerable Render(ZplRenderOptions context) //^FDZEBRA TECHNOLOGIES CORPORATION ^ FS var result = new List(); result.AddRange(RenderPosition(context)); - result.Add($"^BX{RenderFieldOrientation()},{context.Scale(Height)}"); - result.Add($"^FD{Content}^FS"); + result.Add($"^BX{RenderFieldOrientation()},{context.Scale(Height)},{RenderQualityLevel()}"); + result.Add(RenderFieldDataSection()); return result; } - /// - public void SetTemplateContent(string content) - { - Content = content; - } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplDownloadGraphics.cs b/src/BinaryKits.Zpl.Label/Elements/ZplDownloadGraphics.cs index 6c15a705..b89b7f68 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplDownloadGraphics.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplDownloadGraphics.cs @@ -82,6 +82,11 @@ public override IEnumerable Render(ZplRenderOptions context) using (var ms = new MemoryStream()) { + //ImageSharp v3 workaround. +#if NET6_0_OR_GREATER + PngMetadata metadata = image.Metadata.GetPngMetadata(); + metadata.ColorTable = null; +#endif image.Save(ms, new PngEncoder()); objectData = ms.ToArray(); } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplDownloadObjects.cs b/src/BinaryKits.Zpl.Label/Elements/ZplDownloadObjects.cs index c80142e2..b04a2a99 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplDownloadObjects.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplDownloadObjects.cs @@ -54,6 +54,11 @@ public override IEnumerable Render(ZplRenderOptions context) using (var ms = new MemoryStream()) { + //ImageSharp v3 workaround. +#if NET6_0_OR_GREATER + PngMetadata metadata = image.Metadata.GetPngMetadata(); + metadata.ColorTable = null; +#endif image.Save(ms, new PngEncoder()); objectData = ms.ToArray(); } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplElementBase.cs b/src/BinaryKits.Zpl.Label/Elements/ZplElementBase.cs index 99b82f5a..c50a045a 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplElementBase.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplElementBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace BinaryKits.Zpl.Label.Elements @@ -8,7 +8,7 @@ public abstract class ZplElementBase public List Comments { get; protected set; } /// - /// Indicate the rendering process whether this elemenet can be skipped + /// Indicate the rendering process whether this element can be skipped /// public bool IsEnabled { get; set; } @@ -61,6 +61,44 @@ public string RenderFieldOrientation(FieldOrientation fieldOrientation) throw new NotImplementedException("Unknown Field Orientation"); } + public string RenderQualityLevel(QualityLevel qualityLevel) + { + switch (qualityLevel) + { + case QualityLevel.ECC0: + return "0"; + case QualityLevel.ECC50: + return "50"; + case QualityLevel.ECC80: + return "80"; + case QualityLevel.ECC100: + return "100"; + case QualityLevel.ECC140: + return "140"; + case QualityLevel.ECC200: + return "200"; + } + + throw new NotImplementedException("Unknown Quality Level"); + } + + public string RenderFieldJustification(FieldJustification fieldJustification) + { + switch (fieldJustification) + { + case FieldJustification.None: + return string.Empty; + case FieldJustification.Left: + return "0"; + case FieldJustification.Right: + return "1"; + case FieldJustification.Auto: + return "2"; + } + + throw new NotImplementedException("Unknown Field Justification"); + } + public string RenderLineColor(LineColor lineColor) { switch (lineColor) @@ -91,6 +129,16 @@ public string RenderErrorCorrectionLevel(ErrorCorrectionLevel errorCorrectionLev throw new NotImplementedException("Unknown Error Correction Level"); } + /// + /// Render Zpl char for boolean + /// + /// + /// + public string RenderBoolean(bool value) + { + return value ? "Y" : "N"; + } + public string ToZplString() { return ToZplString(new ZplRenderOptions()); diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplFieldBlock.cs b/src/BinaryKits.Zpl.Label/Elements/ZplFieldBlock.cs index 779bb7e4..45550227 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplFieldBlock.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplFieldBlock.cs @@ -28,10 +28,11 @@ public ZplFieldBlock( TextJustification textJustification = TextJustification.Left, int hangingIndent = 0, NewLineConversionMethod newLineConversion = NewLineConversionMethod.ToZplNewLine, - bool useHexadecimalIndicator = true, + char? hexadecimalIndicator = null, bool reversePrint = false, - bool bottomToTop = false) - : base(text, positionX, positionY, font, newLineConversion, useHexadecimalIndicator, reversePrint, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(text, positionX, positionY, font, newLineConversion, hexadecimalIndicator, reversePrint, bottomToTop, useDefaultPosition: useDefaultPosition) { TextJustification = textJustification; Width = width; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplFieldDataElementBase.cs b/src/BinaryKits.Zpl.Label/Elements/ZplFieldDataElementBase.cs new file mode 100644 index 00000000..1cfb9905 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplFieldDataElementBase.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BinaryKits.Zpl.Label.Elements +{ + public class ZplFieldDataElementBase : ZplPositionedElementBase, IFormatElement + { + + public string Content { get; protected set; } + + public FieldOrientation FieldOrientation { get; protected set; } + + public char? HexadecimalIndicator { get; protected set; } + + public ZplFieldDataElementBase( + string content, + int positionX, + int positionY, + FieldOrientation fieldOrientation, + char? hexadecimalIndicator, + bool bottomToTop, + bool useDefaultPosition) + : base(positionX, positionY, bottomToTop, useDefaultPosition) + { + Content = content; + FieldOrientation = fieldOrientation; + HexadecimalIndicator = hexadecimalIndicator; + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + var result = new List(); + result.AddRange(RenderPosition(context)); + result.Add(RenderFieldDataSection()); + + return result; + } + + protected string RenderFieldOrientation() + { + return RenderFieldOrientation(FieldOrientation); + } + + protected string RenderFieldDataSection() + { + var sb = new StringBuilder(); + if (HexadecimalIndicator is char hexIndicator) + { + sb.Append("^FH"); + if (hexIndicator != '_') + { + sb.Append(hexIndicator); + } + } + + sb.Append("^FD"); + sb.Append(this.Content); + sb.Append("^FS"); + + return sb.ToString(); + } + + /// + public void SetTemplateContent(string content) + { + Content = content; + } + + } +} diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrientation.cs b/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrientation.cs index e7290894..5346232f 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrientation.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrientation.cs @@ -8,16 +8,23 @@ namespace BinaryKits.Zpl.Label.Elements public class ZplFieldOrientation : ZplElementBase { public FieldOrientation FieldOrientation { get; private set; } + public FieldJustification FieldJustification { get; private set; } - public ZplFieldOrientation(FieldOrientation fieldOrientation) + /// + /// Field Orientation + /// + /// + /// + public ZplFieldOrientation(FieldOrientation fieldOrientation, FieldJustification fieldJustification = FieldJustification.None) { this.FieldOrientation = fieldOrientation; + this.FieldJustification = fieldJustification; } /// public override IEnumerable Render(ZplRenderOptions context) { - return new[] { $"^FW{RenderFieldOrientation(this.FieldOrientation)}" }; + return new[] { $"^FW{RenderFieldOrientation(this.FieldOrientation)},{RenderFieldJustification(this.FieldJustification)}".TrimEnd(',') }; } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrigin.cs b/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrigin.cs index 7f8d48cc..2951e570 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrigin.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplFieldOrigin.cs @@ -14,23 +14,26 @@ public class ZplFieldOrigin : ZplElementBase { public int PositionX { get; protected set; } public int PositionY { get; protected set; } + public FieldJustification FieldJustification { get; protected set; } /// /// Field Origin /// /// X Position (0-32000) /// Y Position (0-32000) - public ZplFieldOrigin(int positionX, int positionY) + /// + public ZplFieldOrigin(int positionX, int positionY, FieldJustification fieldJustification = FieldJustification.None) { - PositionX = positionX; - PositionY = positionY; + this.PositionX = positionX; + this.PositionY = positionY; + this.FieldJustification = fieldJustification; } /// public override IEnumerable Render(ZplRenderOptions context) { //^FO50,50 - return new string[] { $"^FO{context.Scale(PositionX)},{context.Scale(PositionY)}" }; + return new string[] { $"^FO{context.Scale(this.PositionX)},{context.Scale(this.PositionY)},{RenderFieldJustification(this.FieldJustification)}".TrimEnd(',') }; } /// @@ -41,7 +44,7 @@ public override IEnumerable Render(ZplRenderOptions context) /// public ZplFieldOrigin Offset(int offsetX, int offsetY) { - return new ZplFieldOrigin(PositionX + offsetX, PositionY + offsetY); + return new ZplFieldOrigin(this.PositionX + offsetX, this.PositionY + offsetY, this.FieldJustification); } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplFieldTypeset.cs b/src/BinaryKits.Zpl.Label/Elements/ZplFieldTypeset.cs index 1a6142a7..414c828f 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplFieldTypeset.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplFieldTypeset.cs @@ -16,23 +16,39 @@ public class ZplFieldTypeset : ZplElementBase { public int PositionX { get; protected set; } public int PositionY { get; protected set; } + public bool UseDefaultPosition { get; private set; } + public FieldJustification FieldJustification { get; protected set; } /// /// Field Typeset /// /// X Position (0-32000) /// Y Position (0-32000) - public ZplFieldTypeset(int positionX, int positionY) + /// + /// + public ZplFieldTypeset(int positionX, int positionY, FieldJustification fieldJustification = FieldJustification.None, bool useDefaultPosition = false) { - PositionX = positionX; - PositionY = positionY; + this.PositionX = positionX; + this.PositionY = positionY; + this.FieldJustification = fieldJustification; + this.UseDefaultPosition = useDefaultPosition; } /// public override IEnumerable Render(ZplRenderOptions context) { - //^FO50,50 - return new string[] { $"^FT{context.Scale(PositionX)},{context.Scale(PositionY)}" }; + // When UseDefaultPosition is true, we don't output coordinates in ^FT command + if (UseDefaultPosition) + { + if (FieldJustification != FieldJustification.None) + { + return new string[] { $"^FT,,{RenderFieldJustification(this.FieldJustification)}" }; + } + return new string[] { "^FT" }; + } + + // Normal rendering with coordinates + return new string[] { $"^FT{context.Scale(this.PositionX)},{context.Scale(this.PositionY)},{RenderFieldJustification(this.FieldJustification)}".TrimEnd(',') }; } /// @@ -43,7 +59,7 @@ public override IEnumerable Render(ZplRenderOptions context) /// public ZplFieldTypeset Offset(int offsetX, int offsetY) { - return new ZplFieldTypeset(PositionX + offsetX, PositionY + offsetY); + return new ZplFieldTypeset(this.PositionX + offsetX, this.PositionY + offsetY, this.FieldJustification); } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicBox.cs b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicBox.cs index 1f096bb7..fafe2fa7 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicBox.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicBox.cs @@ -19,8 +19,9 @@ public ZplGraphicBox( LineColor lineColor = LineColor.Black, int cornerRounding = 0, bool reversePrint = false, - bool bottomToTop = false) - : base(positionX, positionY, borderThickness, lineColor, reversePrint, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(positionX, positionY, borderThickness, lineColor, reversePrint, bottomToTop, useDefaultPosition) { Width = width; Height = height; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicCircle.cs b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicCircle.cs index 5a20fe0b..d9362e1c 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicCircle.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicCircle.cs @@ -25,8 +25,9 @@ public ZplGraphicCircle( int borderThickness = 1, LineColor lineColor = LineColor.Black, bool reversePrint = false, - bool bottomToTop = false) - : base(positionX, positionY, borderThickness, lineColor, reversePrint, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(positionX, positionY, borderThickness, lineColor, reversePrint, bottomToTop, useDefaultPosition) { Diameter = diameter; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicElement.cs b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicElement.cs index 20a2dba7..edd223f7 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicElement.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicElement.cs @@ -17,8 +17,9 @@ public ZplGraphicElement( int borderThickness = 1, LineColor lineColor = LineColor.Black, bool reversePrint = false, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(positionX, positionY, bottomToTop, useDefaultPosition) { BorderThickness = borderThickness; LineColor = lineColor; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicField.cs b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicField.cs index fa1c5698..36eb03f0 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicField.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicField.cs @@ -21,8 +21,9 @@ public ZplGraphicField( int bytesPerRow, string data, bool bottomToTop = false, + bool useDefaultPosition = false, char compressionType = 'A') - : base(positionX, positionY, bottomToTop) + : base(positionX, positionY, bottomToTop, useDefaultPosition) { CompressionType = compressionType; BinaryByteCount = binaryByteCount; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicSymbol.cs b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicSymbol.cs index 185ba051..50b86578 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplGraphicSymbol.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplGraphicSymbol.cs @@ -38,8 +38,10 @@ public ZplGraphicSymbol( int positionY, int width, int height, - FieldOrientation fieldOrientation = FieldOrientation.Normal) - : base(positionX, positionY) + FieldOrientation fieldOrientation = FieldOrientation.Normal, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(positionX, positionY, bottomToTop, useDefaultPosition) { Character = character; FieldOrientation = fieldOrientation; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplImageMove.cs b/src/BinaryKits.Zpl.Label/Elements/ZplImageMove.cs index a8a843c7..038d42b1 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplImageMove.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplImageMove.cs @@ -27,8 +27,17 @@ public class ZplImageMove : ZplPositionedElementBase /// /// /// - public ZplImageMove(int positionX, int positionY, char storageDevice, string objectName, string extension) - : base(positionX, positionY) + /// + /// + public ZplImageMove( + int positionX, + int positionY, + char storageDevice, + string objectName, + string extension, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(positionX, positionY, bottomToTop, useDefaultPosition) { StorageDevice = storageDevice; ObjectName = objectName; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplMaxiCode.cs b/src/BinaryKits.Zpl.Label/Elements/ZplMaxiCode.cs index 41cb728d..2360f661 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplMaxiCode.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplMaxiCode.cs @@ -3,17 +3,13 @@ namespace BinaryKits.Zpl.Label.Elements { - public class ZplMaxiCode : ZplPositionedElementBase, IFormatElement + public class ZplMaxiCode : ZplFieldDataElementBase { - public string Content { get; protected set; } - public int Mode { get; private set; } public int Position { get; private set; } public int Total { get; private set; } - - public bool UseHexadecimalIndicator { get; protected set; } /// /// Zpl QrCode @@ -24,8 +20,9 @@ public class ZplMaxiCode : ZplPositionedElementBase, IFormatElement /// 2 (numeric postal code) Default, 3 (alphanumeric postal code), 4 (standard), 5 (full EEC), and 6 (reader programming) /// 1-8, (default: 1) /// 1-8, (default: 1) - /// + /// /// + /// public ZplMaxiCode( string content, int positionX, @@ -33,15 +30,14 @@ public ZplMaxiCode( int mode = 2, int position = 1, int total = 1, - bool useHexadecimalIndicator = false, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + char? hexadecimalIndicator = null, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, positionX, positionY, FieldOrientation.Normal, hexadecimalIndicator, bottomToTop, useDefaultPosition) { - Content = content; Mode = mode; Position = position; Total = total; - UseHexadecimalIndicator = useHexadecimalIndicator; } /// @@ -57,29 +53,5 @@ public override IEnumerable Render(ZplRenderOptions context) return result; } - - protected string RenderFieldDataSection() - { - var sb = new StringBuilder(); - if (UseHexadecimalIndicator) - { - sb.Append("^FH"); - } - - if (Content != null) - { - sb.Append("^FD"); - sb.Append(Content); - sb.Append("^FS"); - } - - return sb.ToString(); - } - - /// - public void SetTemplateContent(string content) - { - Content = content; - } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs b/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs index 41a231e7..30e9e758 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs @@ -5,13 +5,10 @@ namespace BinaryKits.Zpl.Label.Elements /// /// PDF417 Barcode ^B7o,h,s,c,r,t /// - public class ZplPDF417 : ZplPositionedElementBase, IFormatElement + public class ZplPDF417 : ZplFieldDataElementBase { - public int Height { get; protected set; } public int ModuleWidth { get; protected set; } - public string Content { get; protected set; } - public FieldOrientation FieldOrientation { get; protected set; } public int? Columns { get; protected set; } public int? Rows { get; protected set; } public bool Compact { get; protected set; } @@ -28,9 +25,11 @@ public class ZplPDF417 : ZplPositionedElementBase, IFormatElement /// 1-30: Number of data columns to encode. Default will auto balance 1:2 row to column /// 3-90. Number of data columns to encode. Default will auto balance 1:2 row to column /// Truncate right row indicators and stop pattern - /// /// 1-8 This determines the number of error detection and correction code-words to be generated for the symbol.The default level (0) provides only error detection without correction.Increasing the security level adds increasing levels of error correction and increases the symbol size. + /// + /// /// + /// public ZplPDF417( string content, int positionX, @@ -42,24 +41,17 @@ public ZplPDF417( bool compact = false, int securityLevel = 0, FieldOrientation fieldOrientation = FieldOrientation.Normal, - bool bottomToTop = false - ) - : base(positionX, positionY, bottomToTop) + char? hexadecimalIndicator = null, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, positionX, positionY, fieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition) { - FieldOrientation = fieldOrientation; Height = height; ModuleWidth = moduleWidth; Columns = columns; Rows = rows; Compact = compact; SecurityLevel = securityLevel; - Content = content; - } - - - protected string RenderFieldOrientation() - { - return RenderFieldOrientation(FieldOrientation); } /// @@ -71,15 +63,9 @@ public override IEnumerable Render(ZplRenderOptions context) var result = new List(); result.AddRange(RenderPosition(context)); result.Add($"^BX{RenderFieldOrientation()},{context.Scale(Height)}"); - result.Add($"^FD{Content}^FS"); + result.Add(RenderFieldDataSection()); return result; } - - /// - public void SetTemplateContent(string content) - { - Content = content; - } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplPositionedElementBase.cs b/src/BinaryKits.Zpl.Label/Elements/ZplPositionedElementBase.cs index 9f9be178..4ebf32c9 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplPositionedElementBase.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplPositionedElementBase.cs @@ -6,7 +6,7 @@ public abstract class ZplPositionedElementBase : ZplElementBase { public int PositionX { get; private set; } public int PositionY { get; private set; } - + public bool UseDefaultPosition { get; private set; } public ZplFieldOrigin FieldOrigin { get; private set; } public ZplFieldTypeset FieldTypeset { get; private set; } @@ -16,17 +16,21 @@ public abstract class ZplPositionedElementBase : ZplElementBase /// /// /// Use FieldTypeset - public ZplPositionedElementBase(int positionX, int positionY, bool bottomToTop = false) : base() + /// + /// + public ZplPositionedElementBase(int positionX, int positionY, bool bottomToTop, bool useDefaultPosition, FieldJustification fieldJustification = FieldJustification.None) : base() { + this.UseDefaultPosition = useDefaultPosition; + if (bottomToTop) { - FieldTypeset = new ZplFieldTypeset(positionX, positionY); + FieldTypeset = new ZplFieldTypeset(positionX, positionY, fieldJustification, useDefaultPosition); PositionX = positionX; PositionY = positionY; return; } - FieldOrigin = new ZplFieldOrigin(positionX, positionY); + FieldOrigin = new ZplFieldOrigin(positionX, positionY, fieldJustification); PositionX = positionX; PositionY = positionY; } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplQrCode.cs b/src/BinaryKits.Zpl.Label/Elements/ZplQrCode.cs index 4870f745..f6afbcd1 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplQrCode.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplQrCode.cs @@ -1,21 +1,15 @@ using System.Collections.Generic; +using System.Text; namespace BinaryKits.Zpl.Label.Elements { - public class ZplQrCode : ZplPositionedElementBase, IFormatElement + public class ZplQrCode : ZplFieldDataElementBase { - public string Content { get; protected set; } - public int Model { get; private set; } - public int MagnificationFactor { get; private set; } - public ErrorCorrectionLevel ErrorCorrectionLevel { get; private set; } - public int MaskValue { get; private set; } - public FieldOrientation FieldOrientation { get; protected set; } - /// /// Zpl QrCode /// @@ -26,8 +20,10 @@ public class ZplQrCode : ZplPositionedElementBase, IFormatElement /// Size of the QR code, 1 on 150 dpi printers, 2 on 200 dpi printers, 3 on 300 dpi printers, 6 on 600 dpi printers /// /// 0-7, (default: 7) - /// + /// + /// /// + /// public ZplQrCode( string content, int positionX, @@ -37,20 +33,15 @@ public ZplQrCode( ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.HighReliability, int maskValue = 7, FieldOrientation fieldOrientation = FieldOrientation.Normal, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + char? hexadecimalIndicator = null, + bool bottomToTop = false, + bool useDefaultPosition = false) + : base(content, positionX, positionY, fieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition) { - Content = content; Model = model; MagnificationFactor = magnificationFactor; ErrorCorrectionLevel = errorCorrectionLevel; MaskValue = maskValue; - FieldOrientation = fieldOrientation; - } - - protected string RenderFieldOrientation() - { - return RenderFieldOrientation(FieldOrientation); } /// @@ -62,15 +53,26 @@ public override IEnumerable Render(ZplRenderOptions context) var result = new List(); result.AddRange(RenderPosition(context)); result.Add($"^BQ{RenderFieldOrientation()},{Model},{context.Scale(MagnificationFactor)},{RenderErrorCorrectionLevel(ErrorCorrectionLevel)},{MaskValue}"); - result.Add($"^FD{RenderErrorCorrectionLevel(ErrorCorrectionLevel)}A,{Content}^FS"); + result.Add(RenderFieldDataSection()); return result; } - /// - public void SetTemplateContent(string content) + protected new string RenderFieldDataSection() { - Content = content; + var sb = new StringBuilder(); + if (HexadecimalIndicator is char hexIndicator) + { + sb.Append("^FH"); + if (hexIndicator != '_') + { + sb.Append(hexIndicator); + } + } + + sb.Append($"^FD{RenderErrorCorrectionLevel(ErrorCorrectionLevel)}A,{Content}^FS"); + + return sb.ToString(); } } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplRecallGraphic.cs b/src/BinaryKits.Zpl.Label/Elements/ZplRecallGraphic.cs index 4f45e1f5..7c8a2273 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplRecallGraphic.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplRecallGraphic.cs @@ -21,8 +21,9 @@ public ZplRecallGraphic( string imageName, int magnificationFactorX = 1, int magnificationFactorY = 1, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = true) + : base(positionX, positionY, bottomToTop, useDefaultPosition) { if (imageName.Length > 8) { diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplSingleLineFieldBlock.cs b/src/BinaryKits.Zpl.Label/Elements/ZplSingleLineFieldBlock.cs index 21218ee6..64e321cc 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplSingleLineFieldBlock.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplSingleLineFieldBlock.cs @@ -13,9 +13,9 @@ public ZplSingleLineFieldBlock( ZplFont font, TextJustification textJustification = TextJustification.Left, NewLineConversionMethod newLineConversion = NewLineConversionMethod.ToSpace, - bool useHexadecimalIndicator = true, + char? hexadecimalIndicator = null, bool reversePrint = false) - : base(text, positionX, positionY, width, font, 9999, 9999, textJustification, 0, newLineConversion, useHexadecimalIndicator, reversePrint) + : base(text, positionX, positionY, width, font, 9999, 9999, textJustification, 0, newLineConversion, hexadecimalIndicator, reversePrint) { } } diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplTextBlock.cs b/src/BinaryKits.Zpl.Label/Elements/ZplTextBlock.cs index 740e77f4..1f97bc24 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplTextBlock.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplTextBlock.cs @@ -22,8 +22,8 @@ public ZplTextBlock( int height, ZplFont font, NewLineConversionMethod newLineConversion = NewLineConversionMethod.ToSpace, - bool useHexadecimalIndicator = true) - : base(text, positionX, positionY, font, newLineConversion, useHexadecimalIndicator) + char? hexadecimalIndicator = null) + : base(text, positionX, positionY, font, newLineConversion, hexadecimalIndicator) { Width = width; Height = height; diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplTextField.cs b/src/BinaryKits.Zpl.Label/Elements/ZplTextField.cs index de40f751..b2a8ca86 100644 --- a/src/BinaryKits.Zpl.Label/Elements/ZplTextField.cs +++ b/src/BinaryKits.Zpl.Label/Elements/ZplTextField.cs @@ -10,7 +10,7 @@ public class ZplTextField : ZplPositionedElementBase, IFormatElement //^A public ZplFont Font { get; protected set; } //^FH - public bool UseHexadecimalIndicator { get; protected set; } + public char? HexadecimalIndicator { get; protected set; } //^FR public bool ReversePrint { get; protected set; } @@ -27,23 +27,27 @@ public class ZplTextField : ZplPositionedElementBase, IFormatElement /// /// /// - /// + /// /// /// + /// + /// public ZplTextField( string text, int positionX, int positionY, ZplFont font, NewLineConversionMethod newLineConversion = NewLineConversionMethod.ToSpace, - bool useHexadecimalIndicator = true, + char? hexadecimalIndicator = null, bool reversePrint = false, - bool bottomToTop = false) - : base(positionX, positionY, bottomToTop) + bool bottomToTop = false, + bool useDefaultPosition = false, + FieldJustification fieldJustification = FieldJustification.None) + : base(positionX, positionY, bottomToTop, useDefaultPosition, fieldJustification) { Text = text; Font = font; - UseHexadecimalIndicator = useHexadecimalIndicator; + HexadecimalIndicator = hexadecimalIndicator; NewLineConversion = newLineConversion; ReversePrint = reversePrint; } @@ -62,25 +66,28 @@ public override IEnumerable Render(ZplRenderOptions context) protected string RenderFieldDataSection() { var sb = new StringBuilder(); - if (UseHexadecimalIndicator) + if (HexadecimalIndicator is char hexIndicator) { sb.Append("^FH"); + if (hexIndicator != '_') + { + sb.Append(hexIndicator); + } } if (ReversePrint) { sb.Append("^FR"); } + sb.Append("^FD"); if (Text != null) { - sb.Append("^FD"); foreach (var c in Text) { - sb.Append(SanitizeCharacter(c, NewLineConversion, UseHexadecimalIndicator)); + sb.Append(SanitizeCharacter(c, NewLineConversion, HexadecimalIndicator)); } - - sb.Append("^FS"); } + sb.Append("^FS"); return sb.ToString(); } @@ -88,9 +95,9 @@ protected string RenderFieldDataSection() internal static string SanitizeCharacter( char input, NewLineConversionMethod newLineConversion = NewLineConversionMethod.ToSpace, - bool useHexadecimalIndicator = true) + char? hexadecimalIndicator = null) { - if (useHexadecimalIndicator) + if (hexadecimalIndicator != null) { //Convert to hex switch (input) @@ -98,7 +105,7 @@ internal static string SanitizeCharacter( case '_': case '^': case '~': - return "_" + Convert.ToByte(input).ToString("X2"); + return hexadecimalIndicator + Convert.ToByte(input).ToString("X2"); case '\\': return " "; } diff --git a/src/BinaryKits.Zpl.Label/FieldJustification.cs b/src/BinaryKits.Zpl.Label/FieldJustification.cs new file mode 100644 index 00000000..de94f7b0 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/FieldJustification.cs @@ -0,0 +1,25 @@ +namespace BinaryKits.Zpl.Label +{ + /// + /// Text Alignment + /// + public enum FieldJustification + { + /// + /// None + /// + None, + /// + /// Left + /// + Left, + /// + /// Right + /// + Right, + /// + /// Auto (script dependent) + /// + Auto + } +} diff --git a/src/BinaryKits.Zpl.Label/Helpers/ZebraZ64CompressionHelper.cs b/src/BinaryKits.Zpl.Label/Helpers/ZebraZ64CompressionHelper.cs index 793dbc2e..a4a540ba 100644 --- a/src/BinaryKits.Zpl.Label/Helpers/ZebraZ64CompressionHelper.cs +++ b/src/BinaryKits.Zpl.Label/Helpers/ZebraZ64CompressionHelper.cs @@ -87,7 +87,7 @@ internal static byte[] Inflate(byte[] data) /// /// /// - internal static byte[] Deflate(byte[] data, CompressionLevel compressionLevel = (CompressionLevel)3) + internal static byte[] Deflate(byte[] data, CompressionLevel compressionLevel = CompressionLevel.Optimal) { using (var ms = new MemoryStream()) { diff --git a/src/BinaryKits.Zpl.Label/InternationalFont.cs b/src/BinaryKits.Zpl.Label/InternationalFont.cs new file mode 100644 index 00000000..df2fad45 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/InternationalFont.cs @@ -0,0 +1,98 @@ +namespace BinaryKits.Zpl.Label +{ + public enum InternationalFont + { + /// + /// Zebra Code Page 850 - U.S.A. 1 + /// + ZCP850 = 0, + /// + /// Zebra Code Page 850 - U.S.A. 2 + /// + ZCP850_1 = 1, + /// + /// Zebra Code Page 850 - U.K. + /// + ZCP850_2 = 2, + /// + /// Zebra Code Page 850 - Holland + /// + ZCP850_3 = 3, + /// + /// Zebra Code Page 850 - Denmark/Norway + /// + ZCP850_4 = 4, + /// + /// Zebra code Page 850 - Sweden/Finland + /// + ZCP850_5 = 5, + /// + /// Zebra Code Page 850 - Germany + /// + ZCP850_6 = 6, + /// + /// Zebra Code Page 850 - France 1 + /// + ZCP850_7 = 7, + /// + /// Zebra Code Page 850 - France 2 + /// + ZCP850_8 = 8, + /// + /// Zebra Code Page 850 - Italy + /// + ZCP850_9 = 9, + /// + /// Zebra Code Page 850 - Spain + /// + ZCP850_10 = 10, + /// + /// Zebra Code Page 850 - Miscellaneous + /// + ZCP850_11 = 11, + /// + /// Zebra Code Page 850 - Japan + /// + ZCP850_12 = 12, + /// + /// Zebra Code Page 850 + /// + ZCP850_13 = 13, + /// + /// Zebra Code Page 1252 + /// + ZCP1252 = 27, + /// + /// UTF-8 + /// + UTF8 = 28, + /// + /// UTF-16 Big-Endian + /// + UTF16_BE = 29, + /// + /// UTF-16 Little-Endian + /// + UTF16_LE = 30, + /// + /// Zebra Code Page 1250 + /// + ZCP1250 = 31, + /// + /// Zebra Code Page 1251 + /// + ZCP1251 = 33, + /// + /// Zebra Code Page 1253 + /// + ZCP1253 = 34, + /// + /// Zebra Code Page 1254 + /// + ZCP1254 = 35, + /// + /// Zebra Code Page 1255 + /// + ZCP1255 = 36 + } +} diff --git a/src/BinaryKits.Zpl.Label/QualityLevel.cs b/src/BinaryKits.Zpl.Label/QualityLevel.cs new file mode 100644 index 00000000..2dbcfc34 --- /dev/null +++ b/src/BinaryKits.Zpl.Label/QualityLevel.cs @@ -0,0 +1,33 @@ +namespace BinaryKits.Zpl.Label +{ + /// + /// Quality Level + /// + public enum QualityLevel + { + /// + /// ECC Value of 0 + /// + ECC0, + /// + /// ECC Value of 50 + /// + ECC50, + /// + /// ECC Value of 80 + /// + ECC80, + /// + /// ECC Value of 100 + /// + ECC100, + /// + /// ECC Value of 140 + /// + ECC140, + /// + /// ECC Value of 200 + /// + ECC200 + } +} diff --git a/src/BinaryKits.Zpl.Label/ZplConstants.cs b/src/BinaryKits.Zpl.Label/ZplConstants.cs index 330cb3f2..a7ed499a 100644 --- a/src/BinaryKits.Zpl.Label/ZplConstants.cs +++ b/src/BinaryKits.Zpl.Label/ZplConstants.cs @@ -4,18 +4,6 @@ namespace BinaryKits.Zpl.Label { public static class ZplConstants { - public static class InternationalFontEncoding - { - /// - /// Unicode (UTF-8 encoding) - Unicode Character Set - /// - public static readonly string CI28 = "^CI28"; - /// - /// 13 = Zebra Code Page 850 (see page 1194) - /// - public static readonly string CI13 = "^CI13"; - } - public static class Font { public static readonly ZplFont Default = new ZplFont(30, 30, "0", FieldOrientation.Normal); diff --git a/src/BinaryKits.Zpl.Label/ZplEngine.cs b/src/BinaryKits.Zpl.Label/ZplEngine.cs index 1601815e..6161dcf0 100644 --- a/src/BinaryKits.Zpl.Label/ZplEngine.cs +++ b/src/BinaryKits.Zpl.Label/ZplEngine.cs @@ -37,8 +37,6 @@ public List Render(ZplRenderOptions context) result.Add("^LH0,0"); } - result.Add(context.ChangeInternationalFontEncoding); - foreach (var element in this.Where(x => x.IsEnabled)) { //Empty line diff --git a/src/BinaryKits.Zpl.Label/ZplRenderOptions.cs b/src/BinaryKits.Zpl.Label/ZplRenderOptions.cs index ea337e0f..984c7c40 100644 --- a/src/BinaryKits.Zpl.Label/ZplRenderOptions.cs +++ b/src/BinaryKits.Zpl.Label/ZplRenderOptions.cs @@ -14,11 +14,6 @@ public class ZplRenderOptions /// public bool AddDefaultLabelHome { get; set; } - /// - /// ^CI - /// - public string ChangeInternationalFontEncoding { get; set; } - public bool DisplayComments { get; set; } public bool AddEmptyLineBeforeElementStart { get; set; } @@ -53,7 +48,6 @@ public ZplRenderOptions() { AddStartEndFormat = true; AddDefaultLabelHome = true; - ChangeInternationalFontEncoding = ZplConstants.InternationalFontEncoding.CI28; SourcePrintDpi = TargetPrintDpi = 203; } } diff --git a/src/BinaryKits.Zpl.Labelary/BinaryKits.Zpl.Labelary.csproj b/src/BinaryKits.Zpl.Labelary/BinaryKits.Zpl.Labelary.csproj index caabeac3..eaea1af2 100644 --- a/src/BinaryKits.Zpl.Labelary/BinaryKits.Zpl.Labelary.csproj +++ b/src/BinaryKits.Zpl.Labelary/BinaryKits.Zpl.Labelary.csproj @@ -4,7 +4,7 @@ netstandard2.1 This package provides a client for the Labelary API for rendering ZPL data Binary Kits Pte. Ltd. - 1.0.2 + 1.0.3 Binary Kits Pte. Ltd. Zebra ZPL ZPL2 ZPLEmulator ZPLVirtualPrinter ZPLViewer Labelary @@ -21,7 +21,7 @@ - + diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/BinaryKits.Zpl.Protocol.UnitTest.csproj b/src/BinaryKits.Zpl.Protocol.UnitTest/BinaryKits.Zpl.Protocol.UnitTest.csproj index 82f0db5e..946ed24a 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/BinaryKits.Zpl.Protocol.UnitTest.csproj +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/BinaryKits.Zpl.Protocol.UnitTest.csproj @@ -1,19 +1,15 @@  - net6.0 + net8.0 false - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/BarCodeFieldDefaultCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/BarCodeFieldDefaultCommandTest.cs index 7646c9fe..d2fd1b6d 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/BarCodeFieldDefaultCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/BarCodeFieldDefaultCommandTest.cs @@ -23,17 +23,21 @@ public void ToZpl_Default2_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidModuleWidth1_Exception() { - new BarCodeFieldDefaultCommand(0, 3, 10); + Assert.Throws(() => + { + new BarCodeFieldDefaultCommand(0, 3, 10); + }); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidModuleWidth2_Exception() { - new BarCodeFieldDefaultCommand(11, 3, 10); + Assert.Throws(() => + { + new BarCodeFieldDefaultCommand(11, 3, 10); + }); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ChangeAlphanumericDefaultFontCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ChangeAlphanumericDefaultFontCommandTest.cs index 27c4bb66..da2a72ef 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ChangeAlphanumericDefaultFontCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ChangeAlphanumericDefaultFontCommandTest.cs @@ -31,17 +31,17 @@ public void ToZpl_Default3_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidIndividualCharacterHeight_Exception() { - new ChangeAlphanumericDefaultFontCommand('A', 600000); + Assert.Throws(() => + new ChangeAlphanumericDefaultFontCommand('A', 600000)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidIndividualCharacterWidth_Exception() { - new ChangeAlphanumericDefaultFontCommand('A', 1, 600000); + Assert.Throws(() => + new ChangeAlphanumericDefaultFontCommand('A', 1, 600000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code128BarCodeCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code128BarCodeCommandTest.cs index fec418f1..dbe96694 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code128BarCodeCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code128BarCodeCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_Default4_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight1_Exception() { - new Code128BarCodeCommand(barCodeHeight: 0); + Assert.Throws(() => + new Code128BarCodeCommand(barCodeHeight: 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight2_Exception() { - new Code128BarCodeCommand(barCodeHeight: 33000); + Assert.Throws(() => + new Code128BarCodeCommand(barCodeHeight: 33000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code39BarCodeCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code39BarCodeCommandTest.cs index c342962d..e9a5b3be 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code39BarCodeCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Code39BarCodeCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_Default4_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight1_Exception() { - new Code39BarCodeCommand(barCodeHeight: 0); + Assert.Throws(() => + new Code39BarCodeCommand(barCodeHeight: 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight2_Exception() { - new Code39BarCodeCommand(barCodeHeight: 33000); + Assert.Throws(() => + new Code39BarCodeCommand(barCodeHeight: 33000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadGraphicsCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadGraphicsCommandTest.cs index 9d80f65d..607f10b8 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadGraphicsCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadGraphicsCommandTest.cs @@ -31,31 +31,31 @@ public void ToZpl_Default3_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidDeviceToStoreImage1_Exception() { - new DownloadGraphicsCommand("R", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00"); + Assert.Throws(() => + new DownloadGraphicsCommand("R", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidDeviceToStoreImage2_Exception() { - new DownloadGraphicsCommand("R2", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00"); + Assert.Throws(() => + new DownloadGraphicsCommand("R2", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidDeviceToStoreImage3_Exception() { - new DownloadGraphicsCommand("R2", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00"); + Assert.Throws(() => + new DownloadGraphicsCommand("R2", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidDeviceToStoreImage4_Exception() { - new DownloadGraphicsCommand("Z:", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00"); + Assert.Throws(() => + new DownloadGraphicsCommand("Z:", "TEST", 10, 5, "0000FFFFFFFFFFFFFF00")); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadObjectsCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadObjectsCommandTest.cs index b196b1a7..04adeff5 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadObjectsCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/DownloadObjectsCommandTest.cs @@ -68,7 +68,7 @@ public void ParseCommand_InvalidCommand1_Successful() Assert.AreEqual("P", command.ExtensionOfStoredFile); Assert.AreEqual(4, command.TotalNumberOfBytesInFile); Assert.AreEqual(2, command.TotalNumberOfBytesPerRow); - Assert.AreEqual(null, command.Data); + Assert.IsNull(command.Data); } [TestMethod] @@ -79,10 +79,10 @@ public void ParseCommand_InvalidCommand2_Successful() Assert.AreEqual("R:", command.StorageDevice); Assert.AreEqual("UNKNOWN", command.FileName); Assert.AreEqual(char.MinValue, command.FormatDownloadedInDataField); - Assert.AreEqual(null, command.ExtensionOfStoredFile); + Assert.IsNull(command.ExtensionOfStoredFile); Assert.AreEqual(0, command.TotalNumberOfBytesInFile); Assert.AreEqual(0, command.TotalNumberOfBytesPerRow); - Assert.AreEqual(null, command.Data); + Assert.IsNull(command.Data); } } } diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldBlockCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldBlockCommandTest.cs index 2c96b299..9e1ebdf3 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldBlockCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldBlockCommandTest.cs @@ -23,31 +23,31 @@ public void ToZpl_Default2_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_MaximumNumberOfLinesInTextBlockMin_Exception() { - new FieldBlockCommand(maximumNumberOfLinesInTextBlock: 0); + Assert.Throws(() => + new FieldBlockCommand(maximumNumberOfLinesInTextBlock: 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_MaximumNumberOfLinesInTextBlockMax_Exception() { - new FieldBlockCommand(maximumNumberOfLinesInTextBlock: 10000); + Assert.Throws(() => + new FieldBlockCommand(maximumNumberOfLinesInTextBlock: 10000)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_AddOrDeleteSpaceBetweenLinesMin_Exception() { - new FieldBlockCommand(addOrDeleteSpaceBetweenLines: -10000); + Assert.Throws(() => + new FieldBlockCommand(addOrDeleteSpaceBetweenLines: -10000)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_AddOrDeleteSpaceBetweenLinesMax_Exception() { - new FieldBlockCommand(addOrDeleteSpaceBetweenLines: 10000); + Assert.Throws(() => + new FieldBlockCommand(addOrDeleteSpaceBetweenLines: 10000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldOriginCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldOriginCommandTest.cs index f1a0e8ac..491b43b1 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldOriginCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldOriginCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_XnullYnull_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_XMinus10Y0_Exception() { - new FieldOriginCommand(-10, 0); + Assert.Throws(() => + new FieldOriginCommand(-10, 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_X0YMinus10_Exception() { - new FieldOriginCommand(0, -10); + Assert.Throws(() => + new FieldOriginCommand(0, -10)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldTypesetCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldTypesetCommandTest.cs index 3a409e40..f525c9e9 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldTypesetCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/FieldTypesetCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_XnullYnull_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_XMinus10Y0_Exception() { - new FieldTypesetCommand(-10, 0); + Assert.Throws(() => + new FieldTypesetCommand(-10, 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_X0YMinus10_Exception() { - new FieldTypesetCommand(0, -10); + Assert.Throws(() => + new FieldTypesetCommand(0, -10)); } [TestMethod] @@ -94,5 +94,50 @@ public void ParseCommand_ValidCommandXisEmpty_Successful() Assert.AreEqual(0, command.X); Assert.AreEqual(10, command.Y); } + + [TestMethod] + public void ToZpl_WithFieldJustification_Successful() + { + var command = new FieldTypesetCommand(10, 20, 1); + var zplCommand = command.ToZpl(); + Assert.AreEqual("^FT10,20,1", zplCommand); + } + + [TestMethod] + public void ParseCommand_WithFieldJustification_Successful() + { + var command = new FieldTypesetCommand(); + command.ParseCommand("^FT10,20,2"); + Assert.AreEqual(10, command.X); + Assert.AreEqual(20, command.Y); + Assert.AreEqual(2, command.FieldJustification); + } + + [TestMethod] + public void ParseCommand_WithOnlyFieldJustification_Successful() + { + var command = new FieldTypesetCommand(); + command.ParseCommand("^FT,,1"); + Assert.AreEqual(0, command.X); + Assert.AreEqual(0, command.Y); + Assert.AreEqual(1, command.FieldJustification); + } + + [TestMethod] + public void ParseCommand_EmptyCommand_DefaultValues() + { + var command = new FieldTypesetCommand(); + command.ParseCommand("^FT"); + Assert.AreEqual(0, command.X); + Assert.AreEqual(0, command.Y); + Assert.IsNull(command.FieldJustification); + } + + [TestMethod] + public void Constructor_FieldJustificationInvalid_Exception() + { + Assert.Throws(() => + new FieldTypesetCommand(10, 10, 3)); + } } } diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicBoxCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicBoxCommandTest.cs index c294e02c..495db28c 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicBoxCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicBoxCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_WidthNullHeightNull_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_WidthMinus10Height1_Exception() { - new GraphicBoxCommand(-10, 1); + Assert.Throws(() => + new GraphicBoxCommand(-10, 1)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_Widht1HeightMinus10_Exception() { - new GraphicBoxCommand(1, -10); + Assert.Throws(() => + new GraphicBoxCommand(1, -10)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicCircleCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicCircleCommandTest.cs index ec83ef15..7c1b862b 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicCircleCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicCircleCommandTest.cs @@ -47,17 +47,17 @@ public void ToZpl_DefaulValues5_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidCircleDiameter_Exception() { - new GraphicCircleCommand(1); + Assert.Throws(() => + new GraphicCircleCommand(1)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBorderThickness_Exception() { - new GraphicCircleCommand(3, 5000); + Assert.Throws(() => + new GraphicCircleCommand(3, 5000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicFieldCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicFieldCommandTest.cs index 293fa8c6..77e58ff0 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicFieldCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/GraphicFieldCommandTest.cs @@ -31,45 +31,45 @@ public void ToZpl_Default3_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_BinaryByteCountTooLow_Exception() { - new GraphicFieldCommand('A', 0, 1, 1, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 0, 1, 1, "AB")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_BinaryByteCountTooHigh_Exception() { - new GraphicFieldCommand('A', 100000, 1, 1, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 100000, 1, 1, "AB")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_GraphicFieldCountTooLow_Exception() { - new GraphicFieldCommand('A', 1, 0, 1, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 1, 0, 1, "AB")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_GraphicFieldCountTooHigh_Exception() { - new GraphicFieldCommand('A', 1, 100000, 1, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 1, 100000, 1, "AB")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_BytesPerRowTooLow_Exception() { - new GraphicFieldCommand('A', 1, 1, 0, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 1, 1, 0, "AB")); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_BytesPerRowTooHigh_Exception() { - new GraphicFieldCommand('A', 1, 1, 100000, "AB"); + Assert.Throws(() => + new GraphicFieldCommand('A', 1, 1, 100000, "AB")); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Interleaved2Of5BarCodeCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Interleaved2Of5BarCodeCommandTest.cs index c1041412..5b2bed39 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Interleaved2Of5BarCodeCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/Interleaved2Of5BarCodeCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_Default4_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight1_Exception() { - new Interleaved2Of5BarCodeCommand(barCodeHeight: 0); + Assert.Throws(() => + new Interleaved2Of5BarCodeCommand(barCodeHeight: 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidBarCodeHeight2_Exception() { - new Interleaved2Of5BarCodeCommand(barCodeHeight: 33000); + Assert.Throws(() => + new Interleaved2Of5BarCodeCommand(barCodeHeight: 33000)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/LabelHomeCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/LabelHomeCommandTest.cs index a7fb4e2c..efca2981 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/LabelHomeCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/LabelHomeCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_XnullYnull_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_XMinus10Y0_Exception() { - new LabelHomeCommand(-10, 0); + Assert.Throws(() => + new LabelHomeCommand(-10, 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_X0YMinus10_Exception() { - new LabelHomeCommand(0, -10); + Assert.Throws(() => + new LabelHomeCommand(0, -10)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ScalableBitmappedFontCommandTest.cs b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ScalableBitmappedFontCommandTest.cs index c608f26a..36a8cc50 100644 --- a/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ScalableBitmappedFontCommandTest.cs +++ b/src/BinaryKits.Zpl.Protocol.UnitTest/Commands/ScalableBitmappedFontCommandTest.cs @@ -39,17 +39,17 @@ public void ToZpl_Font0Rotated180_Successful() } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidCharacterHeight_Exception() { - new ScalableBitmappedFontCommand('A', Orientation.Normal, characterHeight: 0); + Assert.Throws(() => + new ScalableBitmappedFontCommand('A', Orientation.Normal, characterHeight: 0)); } [TestMethod] - [ExpectedException(typeof(ArgumentException))] public void Constructor_InvalidWidth_Exception() { - new ScalableBitmappedFontCommand('A', Orientation.Normal, width: 0); + Assert.Throws(() => + new ScalableBitmappedFontCommand('A', Orientation.Normal, width: 0)); } [TestMethod] diff --git a/src/BinaryKits.Zpl.Protocol/BinaryKits.Zpl.Protocol.csproj b/src/BinaryKits.Zpl.Protocol/BinaryKits.Zpl.Protocol.csproj index 662f4928..b7825dcf 100644 --- a/src/BinaryKits.Zpl.Protocol/BinaryKits.Zpl.Protocol.csproj +++ b/src/BinaryKits.Zpl.Protocol/BinaryKits.Zpl.Protocol.csproj @@ -1,10 +1,10 @@  - net472;netstandard2.0;net6.0 + net472;netstandard2.0;net8.0 This package contains the zebra protocol of the Zebra Programming Language. It also supports you with image conversion. Binary Kits Pte. Ltd. - 1.0.1 + 1.0.2 Binary Kits Pte. Ltd. Zebra ZPL ZPL2 Printer Protocol @@ -21,11 +21,18 @@ snupkg - - - 2.1.8 - - + + + + + + + + + + + + diff --git a/src/BinaryKits.Zpl.Protocol/Commands/FieldTypesetCommand.cs b/src/BinaryKits.Zpl.Protocol/Commands/FieldTypesetCommand.cs index cb7b46f0..264b5f65 100644 --- a/src/BinaryKits.Zpl.Protocol/Commands/FieldTypesetCommand.cs +++ b/src/BinaryKits.Zpl.Protocol/Commands/FieldTypesetCommand.cs @@ -18,6 +18,11 @@ public class FieldTypesetCommand : CommandBase /// public int Y { get; private set; } = 0; + /// + /// Field justification (0=left, 1=right, 2=auto) + /// + public int? FieldJustification { get; private set; } + /// /// Field Typeset /// @@ -29,9 +34,11 @@ public FieldTypesetCommand() : base("^FT") /// /// x-axis location (0 to 32000) /// y-axis location (0 to 32000) + /// field justification (0=left, 1=right, 2=auto) public FieldTypesetCommand( int? x = null, - int? y = null) + int? y = null, + int? fieldJustification = null) : this() { if (this.ValidateIntParameter(nameof(x), x, 0, 32000)) @@ -43,11 +50,20 @@ public FieldTypesetCommand( { this.Y = y.Value; } + + if (this.ValidateIntParameter(nameof(fieldJustification), fieldJustification, 0, 2)) + { + this.FieldJustification = fieldJustification.Value; + } } /// public override string ToZpl() { + if (FieldJustification.HasValue) + { + return $"{this.CommandPrefix}{this.X},{this.Y},{this.FieldJustification}"; + } return $"{this.CommandPrefix}{this.X},{this.Y}"; } @@ -71,6 +87,14 @@ public override void ParseCommand(string zplCommand) this.Y = y; } } + + if (zplDataParts.Length > 2) + { + if (int.TryParse(zplDataParts[2], out var fieldJustification)) + { + this.FieldJustification = fieldJustification; + } + } } } } diff --git a/src/BinaryKits.Zpl.TestConsole/BinaryKits.Zpl.TestConsole.csproj b/src/BinaryKits.Zpl.TestConsole/BinaryKits.Zpl.TestConsole.csproj index c34a45ba..bef49dd9 100644 --- a/src/BinaryKits.Zpl.TestConsole/BinaryKits.Zpl.TestConsole.csproj +++ b/src/BinaryKits.Zpl.TestConsole/BinaryKits.Zpl.TestConsole.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 @@ -12,7 +12,7 @@ - + diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/BinaryKits.Zpl.Viewer.UnitTest.csproj b/src/BinaryKits.Zpl.Viewer.UnitTest/BinaryKits.Zpl.Viewer.UnitTest.csproj index 4e30eba7..c95f5ff3 100644 --- a/src/BinaryKits.Zpl.Viewer.UnitTest/BinaryKits.Zpl.Viewer.UnitTest.csproj +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/BinaryKits.Zpl.Viewer.UnitTest.csproj @@ -1,19 +1,15 @@  - net6.0 + net8.0 false - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/Data/Zpl/extended_ascii.zpl2 b/src/BinaryKits.Zpl.Viewer.UnitTest/Data/Zpl/extended_ascii.zpl2 new file mode 100644 index 00000000..41a1d11e --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/Data/Zpl/extended_ascii.zpl2 @@ -0,0 +1,6 @@ +^XA + +^CF0,300 +^FO10,10^FH\^FDQt\82^FS + +^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs b/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs index 84fce354..fbda5442 100644 --- a/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs @@ -52,4 +52,4 @@ public void InvertColor() Common.DefaultPrint(test2, "inverted2.png"); } } -} \ No newline at end of file +} diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/StringHelperTest.cs b/src/BinaryKits.Zpl.Viewer.UnitTest/StringHelperTest.cs new file mode 100644 index 00000000..9073560e --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/StringHelperTest.cs @@ -0,0 +1,18 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace BinaryKits.Zpl.Viewer.UnitTest +{ + [TestClass] + public class StringHelperTest + { + /// + /// Test for label containing extended ascii character + /// + [TestMethod] + public void ExtendedASCIICharacter() + { + string zplString = Common.LoadZPL("extended_ascii"); + Common.DefaultPrint(zplString, "extended_ascii.png"); + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/TemplateFormatMergerTest.cs b/src/BinaryKits.Zpl.Viewer.UnitTest/TemplateFormatMergerTest.cs index 75980d0e..39f03576 100644 --- a/src/BinaryKits.Zpl.Viewer.UnitTest/TemplateFormatMergerTest.cs +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/TemplateFormatMergerTest.cs @@ -44,10 +44,10 @@ public void FormatMerging() List merged = formatMerger.MergeFormats(rawLabels); // Then - Assert.AreEqual(1, merged.Count); + Assert.HasCount(1, merged); ZplElementBase[] zplElements = merged[0].ZplElements; - Assert.AreEqual(3, zplElements.Length); + Assert.HasCount(3, zplElements); Assert.AreEqual("one", ((ZplTextField)zplElements[0]).Text); Assert.AreEqual("two", ((ZplTextField)zplElements[1]).Text); Assert.AreEqual("three", ((ZplTextField)zplElements[2]).Text); @@ -67,7 +67,7 @@ public void FormatNotFound() FormatMerger formatMerger = new FormatMerger(); - Assert.ThrowsException(() => formatMerger.MergeFormats(rawLabels)); + Assert.Throws(() => formatMerger.MergeFormats(rawLabels)); } } -} \ No newline at end of file +} diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj b/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj index e4ef089b..d73075a6 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj +++ b/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj @@ -1,13 +1,25 @@  - net6.0 + net8.0 - - + + + + + + + + + + + + + + @@ -90,7 +102,13 @@ PreserveNewest - + + PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -111,12 +129,18 @@ PreserveNewest + + PreserveNewest + PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode128-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode128-102x152.zpl2 index e32c9662..77e2599f 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode128-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode128-102x152.zpl2 @@ -32,6 +32,6 @@ ^FO10,810 ^BY5 ^BCN,100,Y,,,A -^FDABC12345^FS +^FH^FD_41_42_43_31_32_33_34_35^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode39-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode39-102x152.zpl2 index d1507520..1ad2785c 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode39-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode39-102x152.zpl2 @@ -32,6 +32,6 @@ ^FO10,810 ^BY5,3 ^B3N,N,100,Y,N -^FD123ABC^FS +^FH^FD_31_32_33_41_42_43^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 index c962c23a..40a0da43 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 @@ -13,6 +13,6 @@ ^FO10,320 ^BY5,2 ^BAN,100,Y,N -^FD123ABC^FS +^FH^FD_31_32_33_41_42_43^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeEAN13-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeEAN13-102x152.zpl2 index 8e8b7423..377f8335 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeEAN13-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeEAN13-102x152.zpl2 @@ -23,6 +23,6 @@ ^FO60,700 ^BY5 ^BEN,250,Y -^FD123456789012^FS +^FH^FD_31_32_33_34_35_36_37_38_39_30_31_32^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeI2of5-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeI2of5-102x152.zpl2 index fe793aa4..b61ddcfe 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeI2of5-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeI2of5-102x152.zpl2 @@ -32,6 +32,6 @@ ^FO10,810 ^BY5,3 ^B2N,100,Y -^FD123456789012^FS +^FH^FD_31_32_33_34_35_36_37_38_39_30_31_32^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcA-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcA-102x152.zpl2 new file mode 100644 index 00000000..bd411a73 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcA-102x152.zpl2 @@ -0,0 +1,29 @@ +^XA + +^BY2 + +^FO60,30 +^BUN,100,Y,N,N +^FD12345678901^FS + +^FO60,190 +^BUN,100,Y,N,Y +^FD12345678901^FS + +^FO60,350 +^BUN,100,Y,Y,N +^FD12345678901^FS + +^FO60,510 +^BUN,100,Y,Y,Y +^FD12345678901^FS + +^BY3 +^FO60,670 +^BUN,137 +^FD7000002198^FS +^FO372,690 +^BSN,117 +^FD04414^FS + +^XZ diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcE-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcE-102x152.zpl2 new file mode 100644 index 00000000..b62b3613 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodeUpcE-102x152.zpl2 @@ -0,0 +1,33 @@ +^XA + +^BY2 + +^FX short, system 0 +^FO60,30 +^B9N,100,Y,N,Y +^FD981231^FS + +^FX short, system 1 +^FO60,190 +^B9N,100,Y,N,Y +^FD1981231^FS + +^FX long, system 0 +^FO60,350 +^B9N,100,Y,N,Y +^FD9810000123^FS + +^FX long, system 1 +^FO60,510 +^B9N,100,Y,N,Y +^FD19810000123^FS + +^BY3 +^FO60,670 +^B9N,137 +^FD7000002198^FS +^FO240,690 +^BSN,117 +^FD04^FS + +^XZ diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/DataMatrix-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/DataMatrix-102x152.zpl2 index c1626af8..6032c4ae 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/DataMatrix-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/DataMatrix-102x152.zpl2 @@ -4,6 +4,6 @@ ^FO30,70^BXN,4,200^FDABC^FS ^FO30,130^BXN,6,200^FDABC^FS ^FO30,210^BXN,8,200^FDABC^FS -^FO30,310^BXN,10,200^FDABC^FS +^FO30,310^BXN,10,200^FH^FD_41_42_43^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GraphicField-54x86.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GraphicField-54x86.zpl2 new file mode 100644 index 00000000..57ef0003 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GraphicField-54x86.zpl2 @@ -0,0 +1,9 @@ +^XA +^FX GF command parameters: +^FX - format (A/B/C) +^FX - dataBytes (number) +^FX - totalBytes (number) +^FX - rowBytes (number) +^FX - image data (bytes) +^FO33,40^GFA,1860,1860,15,,::X038,X0FE,X0FF,W01C3C,W0781F8,V0FF801E,S0181E6I07,S03838J03,S078FK038,S0FFCK01C,S0EF8002I0F,S0C0030F80078,R01C00FDFC0038,S0C039FFE001C,S0E070C070F8C,S0E06I03FF86,S0F0CI01E1C6,S0FB8L0C7,S0DF8001800C3,R01DDC003C00C3,S0DAJ0C01838,S0F8J0603038,S0FK0207038,S07M03878,S0E1L07C78,S0E38307003E7,S0E3830FC03F7,S0C38607C03F7,R01C30E00C03FE,J08M01C00C00406FE,I03FM01C018J07FE,I063M01C038J037C,I0C1M01C038J07BC,00181M01C038J02B8,00103M018038J0338,00103M01801CK038,00303M01CJ0CI018,00303M01C4I0EI01C,00303M01CE003F8001C,00303M01DFE3E38001C,00303N0DC3E0780038,00103N0EF003D800F8,001838M0E5C0F1807F,00181CM0E07FCI07E,003E0FM0700EJ0E,03FF878L07014I01E,0F03E3CL0383EI03C,1C0071CL03C1CI078,180038EL01CK0FC,180018F8K01EJ01FF8,18001C7F8K0FJ07E3F,18001C7NFCJ0C1FC,1FFE1C7BMFEJ0C19F,0FDFFC78I06001FC0018387C,0C00F87CL038FF870383E,1C00386CL038FF9E0700F8,1C001C4CL0387FF807003C,1CI0ICL0383FF00E001E,1E700CECL01C0F801CI0F,0IFJCL01CJ038I07C,07IFICM0EJ0FJ01E,060078C8M06I01EK0E,06003CC8M06I0F8K07,06001DD8J06006003EL038,07003FBK0600E00FM01C,03C0FB3K0E00E00CN0E,01IF66J03E00E008N07,00FCFECI03E600E018N038,007FFD8007F0600C018N01C,I0MF80600C018O0C,K03FFEI0E01C018O0E,R0E01C018O07,R0E01C018007L038R0E018038003CK038R0E018038I0FK01CR06018038I03EK0CR06018038J0FCJ0CR0601803K07FJ0CR0601803K0E7CI0CR0601803K0E1C0018R0601803K0E180018R0601803K0C3I01,R0601803J01C3I03,R0601803J01C6I03,R0603803J01C6I06,R0703803J01CCI06,R0701803J01CCI0C,R0701803J01D8I0C,R0781803J01980018,R07E1803J03B80018,R07F9803J03BI03,R03BF803J07FI03,R038F803I03FFI06,R0383003803IFI06,R038I03IFC3FI0C,R038J0FF803F801C,R038N03FE018,R038N03CF03,R01CN0387FF,R01CN0383FE,R01CN03803E,R01FN0F807F,R01FCL07F80E3,S0CFCJ07FF80E3,S0C1FF1KFC0DB,S0C03LF1C07B,S0CI0JF00C03F,S0CO0E006,S0EO0F00E,S0EO07FFC,S06O07BFC,S06O038,:S07O01C,:S02P0C,,::::^FS +^XZ diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/HexEscape-54x86.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/HexEscape-54x86.zpl2 new file mode 100644 index 00000000..2095f125 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/HexEscape-54x86.zpl2 @@ -0,0 +1,18 @@ +^XA + +^CI0 +^A0N,30,30 +^FO10,10 +^FH^FDStra_E1e^FS + +^CI27 +^A0N,30,30 +^FO10,50 +^FH^FDStra_DFe^FS + +^CI28 +^A0N,30,30 +^FO10,90 +^FH\^FDStra\C3\9Fe^FS + +^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/MaxiCode-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/MaxiCode-102x152.zpl2 index 8786a6cf..f06aa953 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/MaxiCode-102x152.zpl2 +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/MaxiCode-102x152.zpl2 @@ -5,23 +5,23 @@ ^BD2^FH^FD002840100450000_5B)>_1E01_1D961Z00136071_1DUPSN_1D123X56_1D028_1D_1D001/001_1D011_1DN_1D_1DNEW YORK_1DNY_1E_04^FS ^FX Mode 3 Zebra example 2 -^FO250,250 +^FO230,10 ^BD3^FH^FD066826RS19 _5B)>_1E01_1D961Z00136111_1DUPSN_1D123X56_1D057_1D_1D001/001_1D011_1DN_1D_1DWEST SWINDON_1D_1E_04^FS ^FX Mode 3 Zebra example 3 -^FO500,500 +^FO450,10 ^BD3^FH^FD00163000901 [)>_1E01_1D961Z00004951_1DUPSN_1D06X610_1D159_1D1234567_1D1/1_1D20_1DY_1D634 ALPHA DR_1DSAN JUAN_1DPR_1E_04^FS ^FX Mode 4 -^FO10,500 -^BD4^FD123456789^FS +^FO10,220 +^BD4^FD123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^FS ^FX Mode 5 -^FO10,700 -^BD5^FD123456789^FS +^FO10,430 +^BD5^FD123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^FS ^FX Mode 6 -^FO10,900 -^BD6^FD123456789^FS +^FO10,640 +^BD6^FD123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^FS ^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition3-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition3-102x152.zpl2 new file mode 100644 index 00000000..1bbe2111 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition3-102x152.zpl2 @@ -0,0 +1,6 @@ +^XA +^FT50,50^A0N,50,50^FDText Box^FS +^FT^A0R,50,50^FDText Box^FS +^FT^A0I,50,50^FDText Box^FS +^FT^A0B,50,50^FDText Box^FS +^XZ diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition4-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition4-102x152.zpl2 new file mode 100644 index 00000000..e253c746 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/TextPosition4-102x152.zpl2 @@ -0,0 +1,7 @@ +^XA +^FT10,200^A0N,30,20^FDACME ^FS +^FT^A0N,30,20^FDSummer ^FS +^FT^A0N,60,50^FDClearance ^FS +^FT^A0N,120,100^FDSale ^FS +^XZ + diff --git a/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj b/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj index f1779ed7..07480595 100644 --- a/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj +++ b/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj @@ -1,10 +1,10 @@ - + - net472;netstandard2.0;net6.0 + net472;netstandard2.0;net8.0 This package provides a rendering logic for ZPL data, as an alternative to labelary.com. Binary Kits Pte. Ltd. - 1.2.1 + 1.3.0 Binary Kits Pte. Ltd. Zebra ZPL ZPL2 ZPLEmulator ZPLVirtualPrinter ZPLViewer ZPLParser @@ -21,15 +21,18 @@ latest + + $(DefineConstants);WINDOWS + + - - - + + - - + + diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AnsiCodabarBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AnsiCodabarBarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..a79c6189 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AnsiCodabarBarcodeZplCommandAnalyzer.cs @@ -0,0 +1,70 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class AnsiCodabarBarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public AnsiCodabarBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BK", virtualPrinter) { } + + public override ZplElementBase Analyze(string zplCommand) + { + string[] zplDataParts = this.SplitCommand(zplCommand); + + bool checkDigit = false; + int height = this.VirtualPrinter.BarcodeInfo.Height; + bool printInterpretationLine = true; + bool printInterpretationLineAboveCode = false; + char startCharacter = 'A'; + char stopCharacter = 'A'; + + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + + if (zplDataParts.Length > 1) + { + checkDigit = this.ConvertBoolean(zplDataParts[1], "Y"); + } + + if (zplDataParts.Length > 2 && int.TryParse(zplDataParts[2], out int tmpint)) + { + height = tmpint; + } + + if (zplDataParts.Length > 3) + { + printInterpretationLine = this.ConvertBoolean(zplDataParts[3], "Y"); + } + + if (zplDataParts.Length > 4) + { + printInterpretationLineAboveCode = this.ConvertBoolean(zplDataParts[4]); + } + + if (zplDataParts.Length > 5 && char.TryParse(zplDataParts[6], out char startChar)) + { + startCharacter = startChar; + } + + if (zplDataParts.Length > 6 && char.TryParse(zplDataParts[6], out char stopChar)) + { + stopCharacter = stopChar; + } + + //The field data are processing in the FieldDataZplCommandAnalyzer + this.VirtualPrinter.SetNextElementFieldData(new AnsiCodabarFieldData + { + FieldOrientation = fieldOrientation, + StartCharacter = startCharacter, + StopCharacter = stopCharacter, + Height = height, + CheckDigit = checkDigit, + PrintInterpretationLine = printInterpretationLine, + PrintInterpretationLineAboveCode = printInterpretationLineAboveCode, + }); + + return null; + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AztecBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AztecBarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..f06bc315 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/AztecBarcodeZplCommandAnalyzer.cs @@ -0,0 +1,70 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class AztecBarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public AztecBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BO", virtualPrinter) { } + + /// + public override ZplElementBase Analyze(string zplCommand) + { + string[] zplDataParts = this.SplitCommand(zplCommand); + + int tmpint; + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + int magnificationFactor = 2; + bool extendedChannel = false; + int errorControl = 0; + bool menuSymbol = false; + int symbolCount = 1; + string idField = null; + + if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + { + magnificationFactor = tmpint; + } + + if (zplDataParts.Length > 2) + { + extendedChannel = this.ConvertBoolean(zplDataParts[2]); + } + + if (zplDataParts.Length > 3 && int.TryParse(zplDataParts[3], out tmpint)) + { + errorControl = tmpint; + } + + if (zplDataParts.Length > 4) + { + menuSymbol = this.ConvertBoolean(zplDataParts[4]); + } + + if (zplDataParts.Length > 5 && int.TryParse(zplDataParts[5], out tmpint)) + { + symbolCount = tmpint; + } + + if (zplDataParts.Length > 6) + { + idField = zplDataParts[6]; + } + + this.VirtualPrinter.SetNextElementFieldData(new AztecBarcodeFieldData + { + FieldOrientation = fieldOrientation, + MagnificationFactor = magnificationFactor, + ExtendedChannel = extendedChannel, + ErrorControl = errorControl, + MenuSymbol = menuSymbol, + SymbolCount = symbolCount, + IdField = idField + }); + + return null; + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/BarCodeFieldDefaultZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/BarCodeFieldDefaultZplCommandAnalyzer.cs index f04a137e..ecc2b940 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/BarCodeFieldDefaultZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/BarCodeFieldDefaultZplCommandAnalyzer.cs @@ -9,7 +9,7 @@ public BarCodeFieldDefaultZplCommandAnalyzer(VirtualPrinter virtualPrinter) : ba /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; double tmpdbl; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeAlphanumericDefaultFontZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeAlphanumericDefaultFontZplCommandAnalyzer.cs index 9b457355..02c05f13 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeAlphanumericDefaultFontZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeAlphanumericDefaultFontZplCommandAnalyzer.cs @@ -9,7 +9,7 @@ public ChangeAlphanumericDefaultFontZplCommandAnalyzer(VirtualPrinter virtualPri /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); this.VirtualPrinter.SetFontName(zplDataParts[0]); diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeInternationalFontCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeInternationalFontCommandAnalyzer.cs new file mode 100644 index 00000000..0ea5d987 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ChangeInternationalFontCommandAnalyzer.cs @@ -0,0 +1,27 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; + +using System; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class ChangeInternationalFontCommandAnalyzer : ZplCommandAnalyzerBase + { + + public ChangeInternationalFontCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^CI", virtualPrinter) { } + + public override ZplElementBase Analyze(string zplCommand) + { + string charSet = zplCommand.Substring(this.PrinterCommandPrefix.Length); + + InternationalFont encoding; + if (!Enum.TryParse(charSet, out encoding)) + { + encoding = InternationalFont.ZCP850; + } + + return new ZplChangeInternationalFont(encoding); + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code128BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code128BarcodeZplCommandAnalyzer.cs index b5bd72c8..1a5daa33 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code128BarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code128BarcodeZplCommandAnalyzer.cs @@ -1,3 +1,4 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; @@ -10,9 +11,9 @@ public Code128BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^ /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int height = this.VirtualPrinter.BarcodeInfo.Height; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code39BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code39BarcodeZplCommandAnalyzer.cs index 03ee35be..f53c1f40 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code39BarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code39BarcodeZplCommandAnalyzer.cs @@ -1,3 +1,4 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; @@ -10,7 +11,7 @@ public Code39BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; bool mod43CheckDigit = false; @@ -18,7 +19,7 @@ public override ZplElementBase Analyze(string zplCommand) bool printInterpretationLine = true; bool printInterpretationLineAboveCode = false; - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); if (zplDataParts.Length > 1) { mod43CheckDigit = this.ConvertBoolean(zplDataParts[1]); diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs index 0e657a63..757b0e27 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs @@ -1,4 +1,5 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers @@ -10,7 +11,7 @@ public Code93BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; bool printCheckDigit = false; @@ -18,7 +19,7 @@ public override ZplElementBase Analyze(string zplCommand) bool printInterpretationLine = true; bool printInterpretationLineAboveCode = false; - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) { height = tmpint; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/CodeEAN13BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/CodeEAN13BarcodeZplCommandAnalyzer.cs index 5b75629e..07ab2a14 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/CodeEAN13BarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/CodeEAN13BarcodeZplCommandAnalyzer.cs @@ -1,3 +1,4 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; @@ -10,9 +11,9 @@ public CodeEAN13BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base( /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int height = this.VirtualPrinter.BarcodeInfo.Height; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DataMatrixZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DataMatrixZplCommandAnalyzer.cs index 61ff1724..0c8feba6 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DataMatrixZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DataMatrixZplCommandAnalyzer.cs @@ -1,3 +1,4 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; @@ -10,23 +11,30 @@ public DataMatrixZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BX", /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int height = this.VirtualPrinter.BarcodeInfo.Height; + QualityLevel qualityLevel = QualityLevel.ECC0; if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) { height = tmpint; } + if (zplDataParts.Length > 2) + { + qualityLevel = this.ConvertQualityLevel(zplDataParts[2]); + } + //The field data are processing in the FieldDataZplCommandAnalyzer this.VirtualPrinter.SetNextElementFieldData(new DataMatrixFieldData { FieldOrientation = fieldOrientation, - Height = height + Height = height, + QualityLevel = qualityLevel }); return null; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadFormatCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadFormatCommandAnalyzer.cs index b024ff2d..84f90c36 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadFormatCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadFormatCommandAnalyzer.cs @@ -1,18 +1,19 @@ using BinaryKits.Zpl.Label.Elements; + using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class DownloadFormatCommandAnalyzer : ZplCommandAnalyzerBase { - private static readonly Regex commandRegex = new Regex(@"^\^DF(\w:)?(.*?)?(\..+?)?$", RegexOptions.Compiled); + private static readonly Regex commandRegex = new(@"^\^DF(\w:)?(.*?)?(\..+?)?$", RegexOptions.Compiled); public DownloadFormatCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^DF", virtualPrinter) { } /// public override ZplElementBase Analyze(string zplCommand) { - var commandMatch = commandRegex.Match(zplCommand); + Match commandMatch = commandRegex.Match(zplCommand); if (commandMatch.Success) { char storageDevice = commandMatch.Groups[1].Success ? commandMatch.Groups[1].Value[0] : 'R'; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadGraphicsZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadGraphicsZplCommandAnalyzer.cs index 85684e7d..eddeb2e1 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadGraphicsZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadGraphicsZplCommandAnalyzer.cs @@ -1,28 +1,27 @@ using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Label.ImageConverters; using BinaryKits.Zpl.Viewer.Helpers; -using System; -using System.Data; + using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class DownloadGraphicsZplCommandAnalyzer : ZplCommandAnalyzerBase { - private static readonly Regex commandRegex = new Regex( @"^~DG(\w:)?(.*?\..+?),(\d+),(\d+),(.+)$",RegexOptions.Compiled); + private static readonly Regex commandRegex = new(@"^~DG(\w:)?(.*?\..+?),(\d+),(\d+),(.+)$", RegexOptions.Compiled); - private readonly IPrinterStorage _printerStorage; + private readonly IPrinterStorage printerStorage; public DownloadGraphicsZplCommandAnalyzer(VirtualPrinter virtualPrinter, IPrinterStorage printerStorage) : base("~DG", virtualPrinter) { - this._printerStorage = printerStorage; + this.printerStorage = printerStorage; } /// public override ZplElementBase Analyze(string zplCommand) { - var commandMatch = commandRegex.Match(zplCommand); + Match commandMatch = commandRegex.Match(zplCommand); if (commandMatch.Success) { char storageDevice = commandMatch.Groups[1].Success ? commandMatch.Groups[1].Value[0] : 'R'; @@ -35,10 +34,10 @@ public override ZplElementBase Analyze(string zplCommand) // assert grfImageData.Length == totalNumberOfBytesInGraphic - var converter = new ImageSharpImageConverter(); - var imageData = converter.ConvertImage(grfImageData, numberOfBytesPerRow); + ImageSharpImageConverter converter = new(); + byte[] imageData = converter.ConvertImage(grfImageData, numberOfBytesPerRow); - this._printerStorage.AddFile(storageDevice, imageName, imageData); + this.printerStorage.AddFile(storageDevice, imageName, imageData); } return null; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadObjectsZplCommandAnaylzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadObjectsZplCommandAnaylzer.cs index 9df04838..116db81c 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadObjectsZplCommandAnaylzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/DownloadObjectsZplCommandAnaylzer.cs @@ -1,17 +1,16 @@ using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Label.Helpers; -using BinaryKits.Zpl.Viewer.Helpers; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class DownloadObjectsZplCommandAnaylzer : ZplCommandAnalyzerBase { - private readonly IPrinterStorage _printerStorage; + private readonly IPrinterStorage printerStorage; public DownloadObjectsZplCommandAnaylzer(VirtualPrinter virtualPrinter, IPrinterStorage printerStorage) : base("~DY", virtualPrinter) { - this._printerStorage = printerStorage; + this.printerStorage = printerStorage; } /// @@ -19,7 +18,7 @@ public override ZplElementBase Analyze(string zplCommand) { char storageDevice = zplCommand[this.PrinterCommandPrefix.Length]; - var zplDataParts = this.SplitCommand(zplCommand, 2); + string[] zplDataParts = this.SplitCommand(zplCommand, 2); string objectName = zplDataParts[0]; string formatDownloadedInDataField = zplDataParts[1]; @@ -27,10 +26,10 @@ public override ZplElementBase Analyze(string zplCommand) _ = int.TryParse(zplDataParts[3], out int objectDataLength); _ = int.TryParse(zplDataParts[4], out int totalNumberOfBytesPerRow); - //TODO: Handle case when .GRF data is downloaded using the ~DY command + // TODO: Handle case when .GRF data is downloaded using the ~DY command string dataHex = zplDataParts[5]; - this._printerStorage.AddFile(storageDevice, objectName, ByteHelper.HexToBytes(dataHex)); + this.printerStorage.AddFile(storageDevice, objectName, ByteHelper.HexToBytes(dataHex)); return null; } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldBlockZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldBlockZplCommandAnalyzer.cs index a5a91382..3c1f72c1 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldBlockZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldBlockZplCommandAnalyzer.cs @@ -12,13 +12,13 @@ public FieldBlockZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^FB", /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; int widthOfTextBlockLine = 0; int maximumNumberOfLinesInTextBlock = 1; int addOrDeleteSpaceBetweenLines = 0; - var textJustification = TextJustification.Left; + TextJustification textJustification = TextJustification.Left; int hangingIndentOfTheSecondAndRemainingLines = 0; if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) @@ -31,7 +31,8 @@ public override ZplElementBase Analyze(string zplCommand) maximumNumberOfLinesInTextBlock = tmpint; } - if (zplDataParts.Length > 2 && int.TryParse(zplDataParts[2], out tmpint)) { + if (zplDataParts.Length > 2 && int.TryParse(zplDataParts[2], out tmpint)) + { addOrDeleteSpaceBetweenLines = tmpint; } @@ -51,7 +52,8 @@ public override ZplElementBase Analyze(string zplCommand) } } - if (zplDataParts.Length > 4 && int.TryParse(zplDataParts[4], out tmpint)) { + if (zplDataParts.Length > 4 && int.TryParse(zplDataParts[4], out tmpint)) + { hangingIndentOfTheSecondAndRemainingLines = tmpint; } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs index 1f7406a6..88e80855 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs @@ -1,20 +1,18 @@ -using System; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; -using ZXing; -using ZXing.Datamatrix.Encoder; + +using System; +using System.Text; +using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class FieldDataZplCommandAnalyzer : ZplCommandAnalyzerBase { - private static readonly Regex qrCodeFieldDataNormalRegex = new Regex(@"^(?[HQML])(?[AM]),(?.+)$", RegexOptions.Compiled); - private static readonly Regex qrCodeFieldDataMixedRegex = new Regex(@"^D\d{4}[0-9A-F-a-f]{2},(?[HQML])(?[AM]),(?.+)$", RegexOptions.Compiled); - private static readonly Regex qrCodeFieldDataModeRegex = new Regex(@"^(?:[ANK]|(?:B(?\d{4})))(?.+)$", RegexOptions.Compiled); + private static readonly Regex qrCodeFieldDataNormalRegex = new(@"^(?[HQML])(?[AM]),(?.+)$", RegexOptions.Compiled); + private static readonly Regex qrCodeFieldDataMixedRegex = new(@"^D\d{4}[0-9A-F-a-f]{2},(?[HQML])(?[AM]),(?.+)$", RegexOptions.Compiled); + private static readonly Regex qrCodeFieldDataModeRegex = new(@"^(?:[ANK]|(?:B(?\d{4})))(?.+)$", RegexOptions.Compiled); public FieldDataZplCommandAnalyzer(VirtualPrinter virtualPrinter, string prefix = "^FD") : base(prefix, virtualPrinter) { } @@ -33,7 +31,15 @@ public override ZplElementBase Analyze(string zplCommand) int x = 0; int y = 0; + char? hexadecimalIndicator = this.VirtualPrinter.NextElementFieldHexadecimalIndicator; bool bottomToTop = false; + bool useDefaultPosition = false; + + FieldJustification fieldJustification = this.VirtualPrinter.NextElementFieldJustification; + if (fieldJustification == FieldJustification.None) + { + fieldJustification = this.VirtualPrinter.FieldJustification; + } if (this.VirtualPrinter.NextElementPosition != null) { @@ -41,57 +47,75 @@ public override ZplElementBase Analyze(string zplCommand) y = this.VirtualPrinter.NextElementPosition.Y; bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } if (this.VirtualPrinter.NextElementFieldData != null) { int moduleWidth = this.VirtualPrinter.BarcodeInfo.ModuleWidth; double wideBarToNarrowBarWidthRatio = this.VirtualPrinter.BarcodeInfo.WideBarToNarrowBarWidthRatio; - bool useHexadecimalIndicator = this.VirtualPrinter.NextElementFieldUseHexadecimalIndicator; if (this.VirtualPrinter.NextElementFieldData is Code39BarcodeFieldData code39) { - return new ZplBarcode39(text, x, y, code39.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code39.FieldOrientation, code39.PrintInterpretationLine, code39.PrintInterpretationLineAboveCode, code39.Mod43CheckDigit, bottomToTop: bottomToTop); + return new ZplBarcode39(text, x, y, code39.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code39.FieldOrientation, hexadecimalIndicator, code39.PrintInterpretationLine, code39.PrintInterpretationLineAboveCode, code39.Mod43CheckDigit, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is Code93BarcodeFieldData code93) + else if (this.VirtualPrinter.NextElementFieldData is Code93BarcodeFieldData code93) { - return new ZplBarcode93(text, x, y, code93.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code93.FieldOrientation, code93.PrintInterpretationLine, code93.PrintInterpretationLineAboveCode, code93.PrintCheckDigit, bottomToTop: bottomToTop); + return new ZplBarcode93(text, x, y, code93.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code93.FieldOrientation, hexadecimalIndicator, code93.PrintInterpretationLine, code93.PrintInterpretationLineAboveCode, code93.PrintCheckDigit, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is Code128BarcodeFieldData code128) + else if (this.VirtualPrinter.NextElementFieldData is Code128BarcodeFieldData code128) { - return new ZplBarcode128(text, x, y, code128.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code128.FieldOrientation, code128.PrintInterpretationLine, code128.PrintInterpretationLineAboveCode, bottomToTop, code128.Mode); + return new ZplBarcode128(text, x, y, code128.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code128.FieldOrientation, hexadecimalIndicator, code128.PrintInterpretationLine, code128.PrintInterpretationLineAboveCode, bottomToTop, useDefaultPosition, code128.Mode); } - - if (this.VirtualPrinter.NextElementFieldData is CodeEAN13BarcodeFieldData codeEAN13) + else if (this.VirtualPrinter.NextElementFieldData is CodeEAN13BarcodeFieldData codeEAN13) { - return new ZplBarcodeEan13(text, x, y, codeEAN13.Height, moduleWidth, wideBarToNarrowBarWidthRatio, codeEAN13.FieldOrientation, codeEAN13.PrintInterpretationLine, codeEAN13.PrintInterpretationLineAboveCode, bottomToTop); + return new ZplBarcodeEan13(text, x, y, codeEAN13.Height, moduleWidth, wideBarToNarrowBarWidthRatio, codeEAN13.FieldOrientation, hexadecimalIndicator, codeEAN13.PrintInterpretationLine, codeEAN13.PrintInterpretationLineAboveCode, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is DataMatrixFieldData dataMatrixFieldData) + else if (this.VirtualPrinter.NextElementFieldData is DataMatrixFieldData dataMatrixFieldData) { - return new ZplDataMatrix(text, x, y, dataMatrixFieldData.Height, dataMatrixFieldData.FieldOrientation, bottomToTop); + return new ZplDataMatrix(text, x, y, dataMatrixFieldData.Height, dataMatrixFieldData.QualityLevel, dataMatrixFieldData.FieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is Interleaved2of5BarcodeFieldData interleaved2of5) + else if (this.VirtualPrinter.NextElementFieldData is Interleaved2of5BarcodeFieldData interleaved2of5) { - return new ZplBarcodeInterleaved2of5(text, x, y, interleaved2of5.Height, moduleWidth, wideBarToNarrowBarWidthRatio, interleaved2of5.FieldOrientation, interleaved2of5.PrintInterpretationLine, interleaved2of5.PrintInterpretationLineAboveCode, bottomToTop: bottomToTop); + return new ZplBarcodeInterleaved2of5(text, x, y, interleaved2of5.Height, moduleWidth, wideBarToNarrowBarWidthRatio, interleaved2of5.FieldOrientation, hexadecimalIndicator, interleaved2of5.PrintInterpretationLine, interleaved2of5.PrintInterpretationLineAboveCode, bottomToTop: bottomToTop, useDefaultPosition: useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is MaxiCodeBarcodeFieldData maxiCode) + else if (this.VirtualPrinter.NextElementFieldData is MaxiCodeBarcodeFieldData maxiCode) { - return new ZplMaxiCode(text, x, y, maxiCode.Mode, maxiCode.Position, maxiCode.Total, useHexadecimalIndicator, bottomToTop); + return new ZplMaxiCode(text, x, y, maxiCode.Mode, maxiCode.Position, maxiCode.Total, hexadecimalIndicator, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is QrCodeBarcodeFieldData qrCode) + else if (this.VirtualPrinter.NextElementFieldData is QrCodeBarcodeFieldData qrCode) { - (ErrorCorrectionLevel errorCorrection, string parsedText) = ParseQrCodeFieldData(qrCode, text); - + (ErrorCorrectionLevel errorCorrection, string parsedText) = this.ParseQrCodeFieldData(qrCode, text); // N.B.: always pass Field Orientation Normal to QR codes; the ZPL II standard does not allow rotation - return new ZplQrCode(parsedText, x, y, qrCode.Model, qrCode.MagnificationFactor, errorCorrection, qrCode.MaskValue, Label.FieldOrientation.Normal, bottomToTop); + return new ZplQrCode(parsedText, x, y, qrCode.Model, qrCode.MagnificationFactor, errorCorrection, qrCode.MaskValue, FieldOrientation.Normal, hexadecimalIndicator, bottomToTop, useDefaultPosition); + } + else if (this.VirtualPrinter.NextElementFieldData is UpcABarcodeFieldData upcA) + { + return new ZplBarcodeUpcA(text, x, y, upcA.Height, moduleWidth, wideBarToNarrowBarWidthRatio, upcA.FieldOrientation, hexadecimalIndicator, upcA.PrintInterpretationLine, upcA.PrintInterpretationLineAboveCode, upcA.PrintCheckDigit, bottomToTop, useDefaultPosition); + } + else if (this.VirtualPrinter.NextElementFieldData is UpcEBarcodeFieldData upcE) + { + return new ZplBarcodeUpcE(text, x, y, upcE.Height, moduleWidth, wideBarToNarrowBarWidthRatio, upcE.FieldOrientation, hexadecimalIndicator, upcE.PrintInterpretationLine, upcE.PrintInterpretationLineAboveCode, upcE.PrintCheckDigit, bottomToTop, useDefaultPosition); + } + else if (this.VirtualPrinter.NextElementFieldData is UpcExtensionBarcodeFieldData upcExt) + { + return new ZplBarcodeUpcExtension(text, x, y, upcExt.Height, moduleWidth, wideBarToNarrowBarWidthRatio, upcExt.FieldOrientation, hexadecimalIndicator, upcExt.PrintInterpretationLine, upcExt.PrintInterpretationLineAboveCode, bottomToTop, useDefaultPosition); + } + else if (this.VirtualPrinter.NextElementFieldData is PDF417FieldData pdf147) + { + return new ZplPDF417(text, x, y, pdf147.Height, moduleWidth, pdf147.Columns, pdf147.Rows, pdf147.Compact, pdf147.SecurityLevel, pdf147.FieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition); + } + else if (this.VirtualPrinter.NextElementFieldData is AztecBarcodeFieldData aztec) + { + return new ZplAztecBarcode(text, x, y, aztec.MagnificationFactor, aztec.ExtendedChannel, aztec.ErrorControl, aztec.MenuSymbol, aztec.SymbolCount, aztec.IdField, aztec.FieldOrientation, hexadecimalIndicator, bottomToTop, useDefaultPosition); } - if (this.VirtualPrinter.NextElementFieldData is PDF417FieldData pdf147) + else if (this.VirtualPrinter.NextElementFieldData is AnsiCodabarFieldData codabar) { - return new ZplPDF417(text, x, y, pdf147.Height, moduleWidth, pdf147.Columns, pdf147.Rows, pdf147.Compact, pdf147.SecurityLevel, pdf147.FieldOrientation, bottomToTop); + return new ZplBarcodeAnsiCodabar(text, codabar.StartCharacter, codabar.StopCharacter, x, y, codabar.Height, moduleWidth, wideBarToNarrowBarWidthRatio, codabar.FieldOrientation, hexadecimalIndicator, codabar.PrintInterpretationLine, codabar.PrintInterpretationLineAboveCode, codabar.CheckDigit, bottomToTop, useDefaultPosition); } } - var font = this.GetFontFromVirtualPrinter(); + ZplFont font = this.GetFontFromVirtualPrinter(); if (this.VirtualPrinter.NextFont != null) { font = this.GetNextFontFromVirtualPrinter(); @@ -103,14 +127,14 @@ public override ZplElementBase Analyze(string zplCommand) { int width = this.VirtualPrinter.NextElementFieldBlock.WidthOfTextBlockLine; int maxLineCount = this.VirtualPrinter.NextElementFieldBlock.MaximumNumberOfLinesInTextBlock; - var textJustification = this.VirtualPrinter.NextElementFieldBlock.TextJustification; + TextJustification textJustification = this.VirtualPrinter.NextElementFieldBlock.TextJustification; int lineSpace = this.VirtualPrinter.NextElementFieldBlock.AddOrDeleteSpaceBetweenLines; int hangingIndent = this.VirtualPrinter.NextElementFieldBlock.HangingIndentOfTheSecondAndRemainingLines; - return new ZplFieldBlock(text, x, y, width, font, maxLineCount, lineSpace, textJustification, hangingIndent, reversePrint: reversePrint, bottomToTop: bottomToTop); + return new ZplFieldBlock(text, x, y, width, font, maxLineCount, lineSpace, textJustification, hangingIndent, hexadecimalIndicator: hexadecimalIndicator, reversePrint: reversePrint, bottomToTop: bottomToTop, useDefaultPosition: useDefaultPosition); } - return new ZplTextField(text, x, y, font, reversePrint: reversePrint, bottomToTop: bottomToTop); + return new ZplTextField(text, x, y, font, hexadecimalIndicator: hexadecimalIndicator, reversePrint: reversePrint, bottomToTop: bottomToTop, fieldJustification: fieldJustification, useDefaultPosition: useDefaultPosition); } private (ErrorCorrectionLevel, string) ParseQrCodeFieldData(QrCodeBarcodeFieldData qrCode, string text) @@ -164,7 +188,7 @@ public override ZplElementBase Analyze(string zplCommand) } else if (input == "M") { - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new(); while (fullData.Length > 0) { Match modeMatch = qrCodeFieldDataModeRegex.Match(fullData); @@ -179,14 +203,14 @@ public override ZplElementBase Analyze(string zplCommand) } else { - string[] dataParts = data.Split(new char[] { ',' }, 2); + string[] dataParts = data.Split([','], 2); builder.Append(dataParts[0]); fullData = dataParts.Length > 1 ? dataParts[1] : string.Empty; } } else { - string[] dataParts = fullData.Split(new char[] { ',' }, 2); + string[] dataParts = fullData.Split([','], 2); builder.Append(dataParts[0]); fullData = dataParts.Length > 1 ? dataParts[1] : string.Empty; } @@ -206,7 +230,7 @@ private ZplFont GetFontFromVirtualPrinter() int fontWidth = this.VirtualPrinter.FontWidth; int fontHeight = this.VirtualPrinter.FontHeight; string fontName = this.VirtualPrinter.FontName; - var fieldOrientation = this.VirtualPrinter.FieldOrientation; + FieldOrientation fieldOrientation = this.VirtualPrinter.FieldOrientation; return new ZplFont(fontWidth, fontHeight, fontName, fieldOrientation); } @@ -216,7 +240,7 @@ private ZplFont GetNextFontFromVirtualPrinter() int fontWidth = this.VirtualPrinter.NextFont.FontWidth; int fontHeight = this.VirtualPrinter.NextFont.FontHeight; string fontName = this.VirtualPrinter.NextFont.FontName; - var fieldOrientation = this.VirtualPrinter.NextFont.FieldOrientation; + FieldOrientation fieldOrientation = this.VirtualPrinter.NextFont.FieldOrientation; return new ZplFont(fontWidth, fontHeight, fontName, fieldOrientation); } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldHexadecimalZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldHexadecimalZplCommandAnalyzer.cs index 0565578c..f1b015ae 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldHexadecimalZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldHexadecimalZplCommandAnalyzer.cs @@ -1,5 +1,4 @@ using BinaryKits.Zpl.Label.Elements; -using BinaryKits.Zpl.Viewer.Helpers; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -10,17 +9,14 @@ public FieldHexadecimalZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base( /// public override ZplElementBase Analyze(string zplCommand) { - this.VirtualPrinter.SetNextElementFieldUseHexadecimalIndicator(); - var zplDataParts = this.SplitCommand(zplCommand); - - char Indicator = '_'; - - if ((zplDataParts.Length > 0) && (zplDataParts[0].Length > 0)) + char indicator = '_'; + string[] zplDataParts = this.SplitCommand(zplCommand); + if (zplDataParts.Length > 0 && zplDataParts[0].Length > 0) { - Indicator = zplDataParts[0][0]; + indicator = zplDataParts[0][0]; } - StringHelper.ReplaceChar = Indicator; + this.VirtualPrinter.SetNextElementFieldHexadecimalIndicator(indicator); return null; } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldNumberCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldNumberCommandAnalyzer.cs index b33e224a..1d526276 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldNumberCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldNumberCommandAnalyzer.cs @@ -9,7 +9,7 @@ public FieldNumberCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^FN", v /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; int fieldNumber = 0; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOrientationZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOrientationZplCommandAnalyzer.cs index c98a8cbc..fb7ba974 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOrientationZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOrientationZplCommandAnalyzer.cs @@ -1,4 +1,5 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -9,13 +10,19 @@ public FieldOrientationZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base( /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); if (zplDataParts.Length > 0) { - var fieldOrientation = ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); this.VirtualPrinter.SetFieldOrientation(fieldOrientation); } + if (zplDataParts.Length > 1) + { + FieldJustification fieldJustification = this.ConvertFieldJustification(zplDataParts[1]); + this.VirtualPrinter.SetFieldJustification(fieldJustification); + } + return null; } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOriginZplCommandAnalzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOriginZplCommandAnalzer.cs index 15d0d904..e7e363a5 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOriginZplCommandAnalzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldOriginZplCommandAnalzer.cs @@ -1,4 +1,5 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -9,22 +10,31 @@ public FieldOriginZplCommandAnalzer(VirtualPrinter virtualPrinter) : base("^FO", /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - int tmpint; + decimal tmpdec; int x = 0; int y = 0; - // TODO: Field Justification - //int z = 0; - if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) + if (zplDataParts.Length > 0 && + decimal.TryParse(zplDataParts[0], out tmpdec) && + int.MinValue <= tmpdec && tmpdec <= int.MaxValue) { - x = tmpint; + x = decimal.ToInt32(tmpdec); } - if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + + if (zplDataParts.Length > 1 && + decimal.TryParse(zplDataParts[1], out tmpdec) && + int.MinValue <= tmpdec && tmpdec <= int.MaxValue) + { + y = decimal.ToInt32(tmpdec); + } + + if (zplDataParts.Length > 2) { - y = tmpint; + FieldJustification fieldJustification = this.ConvertFieldJustification(zplDataParts[2]); + this.VirtualPrinter.SetNextElementFieldJustification(fieldJustification); } if (this.VirtualPrinter.LabelHomePosition != null) diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldSeparatorZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldSeparatorZplCommandAnalyzer.cs index 16f56867..697541a5 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldSeparatorZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldSeparatorZplCommandAnalyzer.cs @@ -4,12 +4,12 @@ namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class FieldSeparatorZplCommandAnalyzer : ZplCommandAnalyzerBase { - private ZplCommandAnalyzerBase _fieldDataAnalyzer; + private readonly ZplCommandAnalyzerBase fieldDataAnalyzer; public FieldSeparatorZplCommandAnalyzer(VirtualPrinter virtualPrinter, ZplCommandAnalyzerBase fieldDataAnalyzer) : base("^FS", virtualPrinter) { - _fieldDataAnalyzer = fieldDataAnalyzer; + this.fieldDataAnalyzer = fieldDataAnalyzer; } /// @@ -22,7 +22,7 @@ public override ZplElementBase Analyze(string zplCommand) if (fieldNumber.HasValue) { this.VirtualPrinter.ClearNextFieldNumber(); - ZplElementBase dataElement = _fieldDataAnalyzer.Analyze(zplCommand); + ZplElementBase dataElement = this.fieldDataAnalyzer.Analyze(zplCommand); element = new ZplFieldNumber(fieldNumber.Value, dataElement); } @@ -30,7 +30,8 @@ public override ZplElementBase Analyze(string zplCommand) this.VirtualPrinter.ClearNextElementFieldBlock(); this.VirtualPrinter.ClearNextElementFieldData(); this.VirtualPrinter.ClearNextElementFieldReverse(); - this.VirtualPrinter.ClearNextElementFieldUseHexadecimalIndicator(); + this.VirtualPrinter.ClearNextElementFieldHexadecimalIndicator(); + this.VirtualPrinter.ClearNextElementFieldJustification(); this.VirtualPrinter.ClearNextFont(); this.VirtualPrinter.ClearComments(); diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldTypesetZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldTypesetZplCommandAnalyzer.cs index 1c6b20b7..225d017f 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldTypesetZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldTypesetZplCommandAnalyzer.cs @@ -1,4 +1,5 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -9,22 +10,56 @@ public FieldTypesetZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^FT /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - int tmpint; + decimal tmpdec; int x = 0; int y = 0; - // TODO: Field Justification - //int z = 0; + bool useDefaultPosition = false; - if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) + // Handle missing coordinates - when coordinates are missing, use default positioning + if (zplDataParts.Length == 0 || string.IsNullOrEmpty(zplDataParts[0])) { - x = tmpint; + // No coordinates specified - use default position + useDefaultPosition = true; + } + else + { + if (decimal.TryParse(zplDataParts[0], out tmpdec) && + int.MinValue <= tmpdec && tmpdec <= int.MaxValue) + { + x = decimal.ToInt32(tmpdec); + } + else + { + // Empty or invalid x coordinate - use default position + useDefaultPosition = true; + } + } + + if (zplDataParts.Length > 1 && !string.IsNullOrEmpty(zplDataParts[1])) + { + if (decimal.TryParse(zplDataParts[1], out tmpdec) && + int.MinValue <= tmpdec && tmpdec <= int.MaxValue) + { + y = decimal.ToInt32(tmpdec); + } + else if (!useDefaultPosition) + { + // Invalid y coordinate but x was valid - use default position + useDefaultPosition = true; + } + } + else if (zplDataParts.Length > 1) + { + // Empty y coordinate - use default position + useDefaultPosition = true; } - if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + if (zplDataParts.Length > 2) { - y = tmpint; + FieldJustification fieldJustification = this.ConvertFieldJustification(zplDataParts[2]); + this.VirtualPrinter.SetNextElementFieldJustification(fieldJustification); } if (this.VirtualPrinter.LabelHomePosition != null) @@ -33,7 +68,7 @@ public override ZplElementBase Analyze(string zplCommand) y += this.VirtualPrinter.LabelHomePosition.Y; } - this.VirtualPrinter.SetNextElementPosition(x, y, calculateFromBottom: true); + this.VirtualPrinter.SetNextElementPosition(x, y, true, useDefaultPosition); return null; } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs index 581a6509..376dc30b 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs @@ -1,7 +1,7 @@ namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { - // todo: fix virtual printer, must enable the MC command - // todo: factor out common parts from FieldDataZplCommandAnalyzer so both can inherit + // TODO: fix virtual printer, must enable the MC command + // TODO: factor out common parts from FieldDataZplCommandAnalyzer so both can inherit // This is currently just a hack to be able to visualize single ups zpl. // The FV command is normally used with the MC command when printing multiple labels of a same pattern. // The MC command allows us to "save" the first label as a template @@ -9,6 +9,6 @@ // Subsequent labels only require FV to draw the variable parts. public class FieldVariableZplCommandAnalyzer : FieldDataZplCommandAnalyzer { - public FieldVariableZplCommandAnalyzer(VirtualPrinter virtualPrinter): base(virtualPrinter, "^FV") { } + public FieldVariableZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base(virtualPrinter, "^FV") { } } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicBoxZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicBoxZplCommandAnalyzer.cs index 79874e07..9bcf9f94 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicBoxZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicBoxZplCommandAnalyzer.cs @@ -14,12 +14,13 @@ public override ZplElementBase Analyze(string zplCommand) int width = 1; int height = 1; int borderThickness = 1; - var lineColor = LineColor.Black; + LineColor lineColor = LineColor.Black; int cornerRounding = 0; int x = 0; int y = 0; bool bottomToTop = false; + bool useDefaultPosition = false; if (this.VirtualPrinter.NextElementPosition != null) { @@ -27,15 +28,18 @@ public override ZplElementBase Analyze(string zplCommand) y = this.VirtualPrinter.NextElementPosition.Y; bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) { - width= tmpint; + if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) + { + width = tmpint; } - if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) { + if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + { height = tmpint; } @@ -57,7 +61,7 @@ public override ZplElementBase Analyze(string zplCommand) bool reversePrint = this.VirtualPrinter.NextElementFieldReverse || this.VirtualPrinter.LabelReverse; - return new ZplGraphicBox(x, y, width, height, borderThickness, lineColor, cornerRounding, reversePrint, bottomToTop); + return new ZplGraphicBox(x, y, width, height, borderThickness, lineColor, cornerRounding, reversePrint, bottomToTop, useDefaultPosition); } } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicCircleZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicCircleZplCommandAnalyzer.cs index 4ccdf2a1..46432106 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicCircleZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicCircleZplCommandAnalyzer.cs @@ -13,20 +13,23 @@ public override ZplElementBase Analyze(string zplCommand) int tmpint; int circleDiameter = 3; int borderThickness = 1; - var lineColor = LineColor.Black; + LineColor lineColor = LineColor.Black; int x = 0; int y = 0; bool bottomToTop = false; + bool useDefaultPosition = false; if (this.VirtualPrinter.NextElementPosition != null) { x = this.VirtualPrinter.NextElementPosition.X; y = this.VirtualPrinter.NextElementPosition.Y; + bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); if (zplDataParts.Length > 0 && int.TryParse(zplDataParts[0], out tmpint)) { @@ -45,8 +48,8 @@ public override ZplElementBase Analyze(string zplCommand) } bool reversePrint = this.VirtualPrinter.NextElementFieldReverse || this.VirtualPrinter.LabelReverse; - - return new ZplGraphicCircle(x, y, circleDiameter, borderThickness, lineColor, reversePrint, bottomToTop); + + return new ZplGraphicCircle(x, y, circleDiameter, borderThickness, lineColor, reversePrint, bottomToTop, useDefaultPosition); } } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicFieldZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicFieldZplCommandAnalyzer.cs index 997ed5d7..21d7e7ec 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicFieldZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/GraphicFieldZplCommandAnalyzer.cs @@ -20,6 +20,7 @@ public override ZplElementBase Analyze(string zplCommand) int x = 0; int y = 0; bool bottomToTop = false; + bool useDefaultPosition = false; if (this.VirtualPrinter.NextElementPosition != null) { @@ -27,9 +28,10 @@ public override ZplElementBase Analyze(string zplCommand) y = this.VirtualPrinter.NextElementPosition.Y; bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); char compressionType = zplDataParts[0][0]; @@ -50,15 +52,15 @@ public override ZplElementBase Analyze(string zplCommand) //fourth comma is the start of the image data int indexOfFourthComma = this.IndexOfNthCharacter(zplCommand, 4, ','); - string dataHex = zplCommand.Substring(indexOfFourthComma + 1); + string dataHex = zplCommand.Substring(indexOfFourthComma + 1).TrimStart(); byte[] grfImageData = ImageHelper.GetImageBytes(dataHex, bytesPerRow); - var converter = new ImageSharpImageConverter(); - var imageData = converter.ConvertImage(grfImageData, bytesPerRow); + ImageSharpImageConverter converter = new(); + byte[] imageData = converter.ConvertImage(grfImageData, bytesPerRow); dataHex = ByteHelper.BytesToHex(imageData); - return new ZplGraphicField(x, y, binaryByteCount, graphicFieldCount, bytesPerRow, dataHex, bottomToTop: bottomToTop, compressionType); + return new ZplGraphicField(x, y, binaryByteCount, graphicFieldCount, bytesPerRow, dataHex, bottomToTop, useDefaultPosition, compressionType); } } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ImageMoveZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ImageMoveZplCommandAnalyzer.cs index 3fca387f..6eff56fc 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ImageMoveZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ImageMoveZplCommandAnalyzer.cs @@ -11,11 +11,16 @@ public override ZplElementBase Analyze(string zplCommand) { int x = 0; int y = 0; + bool bottomToTop = false; + bool useDefaultPosition = false; if (this.VirtualPrinter.NextElementPosition != null) { x = this.VirtualPrinter.NextElementPosition.X; y = this.VirtualPrinter.NextElementPosition.Y; + + bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } string zplCommandData = zplCommand.Substring(this.PrinterCommandPrefix.Length); @@ -25,7 +30,7 @@ public override ZplElementBase Analyze(string zplCommand) string objectName = zplCommandData.Substring(2); - return new ZplImageMove(x, y, storageDevice, objectName, string.Empty); + return new ZplImageMove(x, y, storageDevice, objectName, string.Empty, bottomToTop, useDefaultPosition); } } } diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Interleaved2of5BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Interleaved2of5BarcodeZplCommandAnalyzer.cs index 3b4ad1d0..6dfdfe45 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Interleaved2of5BarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Interleaved2of5BarcodeZplCommandAnalyzer.cs @@ -1,3 +1,4 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; @@ -10,9 +11,9 @@ public Interleaved2of5BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int height = this.VirtualPrinter.BarcodeInfo.Height; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelHomeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelHomeZplCommandAnalyzer.cs index b26e66e8..f048de21 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelHomeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelHomeZplCommandAnalyzer.cs @@ -9,7 +9,7 @@ public LabelHomeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^LH", /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int tmpint; int x = 0; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelReversePrintZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelReversePrintZplCommandAnalyzer.cs index fa165ab4..1adbecad 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelReversePrintZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/LabelReversePrintZplCommandAnalyzer.cs @@ -9,7 +9,7 @@ public LabelReversePrintZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); bool reverse = false; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/MaxiCodeBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/MaxiCodeBarcodeZplCommandAnalyzer.cs index 9054094a..d797a519 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/MaxiCodeBarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/MaxiCodeBarcodeZplCommandAnalyzer.cs @@ -1,6 +1,5 @@ using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; -using System; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -11,15 +10,15 @@ public MaxiCodeBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base(" /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); int mode = 2; int position = 1; int total = 1; - + if (zplDataParts[0] != "") { - mode = Int32.Parse(zplDataParts[0]); + mode = int.Parse(zplDataParts[0]); } int tmpint; @@ -33,8 +32,11 @@ public override ZplElementBase Analyze(string zplCommand) total = tmpint; } - this.VirtualPrinter.SetNextElementFieldData(new MaxiCodeBarcodeFieldData { - Mode = mode, Position = position, Total = total, + this.VirtualPrinter.SetNextElementFieldData(new MaxiCodeBarcodeFieldData + { + Mode = mode, + Position = position, + Total = total, }); return null; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs index 6d696c90..a8cba2e9 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs @@ -1,6 +1,7 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Models; + using System; using System.Globalization; @@ -12,7 +13,7 @@ public PDF417ZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B7", vir /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); // reusable buffer int tmpint; @@ -27,8 +28,8 @@ public override ZplElementBase Analyze(string zplCommand) * compact */ - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); - + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + int height = this.VirtualPrinter.BarcodeInfo.Height; if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) { @@ -37,8 +38,8 @@ public override ZplElementBase Analyze(string zplCommand) else if (zplDataParts.Length > 1) { //Sometimes a decimal is given, this works around that. - var tempDecimal = Convert.ToDecimal(zplDataParts[1], new CultureInfo("en-US")); - var tempHeight = (int)Math.Floor(tempDecimal); + decimal tempDecimal = Convert.ToDecimal(zplDataParts[1], new CultureInfo("en-US")); + int tempHeight = (int)Math.Floor(tempDecimal); if (tempHeight > 0) { height = tempHeight; @@ -62,11 +63,11 @@ public override ZplElementBase Analyze(string zplCommand) { rows = tmpint; } - + bool compact = false; if (zplDataParts.Length > 5) { - compact = ConvertBoolean(zplDataParts[5]); + compact = this.ConvertBoolean(zplDataParts[5]); } //The field data are processing in the FieldDataZplCommandAnalyzer diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/QrCodeBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/QrCodeBarcodeZplCommandAnalyzer.cs index 8b52c9ef..fdeb6f49 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/QrCodeBarcodeZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/QrCodeBarcodeZplCommandAnalyzer.cs @@ -11,14 +11,14 @@ public QrCodeBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B /// public override ZplElementBase Analyze(string zplCommand) { - var zplDataParts = this.SplitCommand(zplCommand); + string[] zplDataParts = this.SplitCommand(zplCommand); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int model = 2; int magnificationFactor = 3; - var errorCorrection = ErrorCorrectionLevel.HighReliability; + ErrorCorrectionLevel errorCorrection = ErrorCorrectionLevel.HighReliability; int maskValue = 7; if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/RecallGraphicZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/RecallGraphicZplCommandAnalyzer.cs index a29a3b53..c8b00582 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/RecallGraphicZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/RecallGraphicZplCommandAnalyzer.cs @@ -1,11 +1,12 @@ using BinaryKits.Zpl.Label.Elements; + using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { public class RecallGraphicZplCommandAnalyzer : ZplCommandAnalyzerBase { - private static readonly Regex commandRegex = new Regex(@"^\^XG(\w:)?(.*?\..+?)(?:,(\d*))?(?:,(\d*))?$", RegexOptions.Compiled); + private static readonly Regex commandRegex = new(@"^\^XG(\w:)?(.*?\..+?)(?:,(\d*))?(?:,(\d*))?$", RegexOptions.Compiled); public RecallGraphicZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^XG", virtualPrinter) { } @@ -15,15 +16,17 @@ public override ZplElementBase Analyze(string zplCommand) int x = 0; int y = 0; bool bottomToTop = false; + bool useDefaultPosition = false; if (this.VirtualPrinter.NextElementPosition != null) { x = this.VirtualPrinter.NextElementPosition.X; y = this.VirtualPrinter.NextElementPosition.Y; bottomToTop = this.VirtualPrinter.NextElementPosition.CalculateFromBottom; + useDefaultPosition = this.VirtualPrinter.NextElementPosition.UseDefaultPosition; } - var commandMatch = commandRegex.Match(zplCommand); + Match commandMatch = commandRegex.Match(zplCommand); if (commandMatch.Success) { @@ -32,7 +35,7 @@ public override ZplElementBase Analyze(string zplCommand) int magnificationFactorX = commandMatch.Groups[3].Success ? int.Parse(commandMatch.Groups[3].Value) : 1; int magnificationFactorY = commandMatch.Groups[4].Success ? int.Parse(commandMatch.Groups[4].Value) : 1; - return new ZplRecallGraphic(x, y, storageDevice, imageName, magnificationFactorX, magnificationFactorY, bottomToTop); + return new ZplRecallGraphic(x, y, storageDevice, imageName, magnificationFactorX, magnificationFactorY, bottomToTop, useDefaultPosition); } return null; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ScalableBitmappedFontZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ScalableBitmappedFontZplCommandAnalyzer.cs index 4779a3ad..7bd3e4fe 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ScalableBitmappedFontZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ScalableBitmappedFontZplCommandAnalyzer.cs @@ -1,4 +1,5 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; namespace BinaryKits.Zpl.Viewer.CommandAnalyzers { @@ -11,9 +12,9 @@ public override ZplElementBase Analyze(string zplCommand) { string fontName = zplCommand[this.PrinterCommandPrefix.Length].ToString(); - var zplDataParts = this.SplitCommand(zplCommand, 1); + string[] zplDataParts = this.SplitCommand(zplCommand, 1); - var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); int tmpint; int? parsedHeight = null; @@ -29,8 +30,8 @@ public override ZplElementBase Analyze(string zplCommand) parsedWidth = tmpint; } - int fontHeight = parsedHeight ?? (parsedWidth ?? this.VirtualPrinter.FontHeight); - int fontWidth = parsedWidth ?? (parsedHeight ?? this.VirtualPrinter.FontWidth); + int fontHeight = parsedHeight ?? parsedWidth ?? this.VirtualPrinter.FontHeight; + int fontWidth = parsedWidth ?? parsedHeight ?? this.VirtualPrinter.FontWidth; this.VirtualPrinter.SetNextFont(fontName, fieldOrientation, fontWidth, fontHeight); diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcABarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcABarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..64480ae4 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcABarcodeZplCommandAnalyzer.cs @@ -0,0 +1,55 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class UpcABarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public UpcABarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BU", virtualPrinter) { } + + /// + public override ZplElementBase Analyze(string zplCommand) + { + string[] zplDataParts = this.SplitCommand(zplCommand); + + int tmpint; + int height = this.VirtualPrinter.BarcodeInfo.Height; + bool printInterpretationLine = true; + bool printInterpretationLineAboveCode = false; + bool printCheckDigit = true; + + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + { + height = tmpint; + } + + if (zplDataParts.Length > 2) + { + printInterpretationLine = this.ConvertBoolean(zplDataParts[2], "Y"); + } + + if (zplDataParts.Length > 3) + { + printInterpretationLineAboveCode = this.ConvertBoolean(zplDataParts[3]); + } + + if (zplDataParts.Length > 4) + { + printCheckDigit = this.ConvertBoolean(zplDataParts[4]); + } + + this.VirtualPrinter.SetNextElementFieldData(new UpcABarcodeFieldData + { + FieldOrientation = fieldOrientation, + Height = height, + PrintInterpretationLine = printInterpretationLine, + PrintInterpretationLineAboveCode = printInterpretationLineAboveCode, + PrintCheckDigit = printCheckDigit + }); + + return null; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcEBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcEBarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..57780778 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcEBarcodeZplCommandAnalyzer.cs @@ -0,0 +1,55 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class UpcEBarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public UpcEBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B9", virtualPrinter) { } + + /// + public override ZplElementBase Analyze(string zplCommand) + { + string[] zplDataParts = this.SplitCommand(zplCommand); + + int tmpint; + int height = this.VirtualPrinter.BarcodeInfo.Height; + bool printInterpretationLine = true; + bool printInterpretationLineAboveCode = false; + bool printCheckDigit = true; + + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + { + height = tmpint; + } + + if (zplDataParts.Length > 2) + { + printInterpretationLine = this.ConvertBoolean(zplDataParts[2], "Y"); + } + + if (zplDataParts.Length > 3) + { + printInterpretationLineAboveCode = this.ConvertBoolean(zplDataParts[3]); + } + + if (zplDataParts.Length > 4) + { + printCheckDigit = this.ConvertBoolean(zplDataParts[4]); + } + + this.VirtualPrinter.SetNextElementFieldData(new UpcEBarcodeFieldData + { + FieldOrientation = fieldOrientation, + Height = height, + PrintInterpretationLine = printInterpretationLine, + PrintInterpretationLineAboveCode = printInterpretationLineAboveCode, + PrintCheckDigit = printCheckDigit + }); + + return null; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcExtensionBarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcExtensionBarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..fe2f077b --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/UpcExtensionBarcodeZplCommandAnalyzer.cs @@ -0,0 +1,48 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class UpcExtensionBarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public UpcExtensionBarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BS", virtualPrinter) { } + + /// + public override ZplElementBase Analyze(string zplCommand) + { + string[] zplDataParts = this.SplitCommand(zplCommand); + + int tmpint; + int height = this.VirtualPrinter.BarcodeInfo.Height; + bool printInterpretationLine = true; + bool printInterpretationLineAboveCode = true; + + FieldOrientation fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); + if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) + { + height = tmpint; + } + + if (zplDataParts.Length > 2) + { + printInterpretationLine = this.ConvertBoolean(zplDataParts[2], "Y"); + } + + if (zplDataParts.Length > 3) + { + printInterpretationLineAboveCode = this.ConvertBoolean(zplDataParts[3], "Y"); + } + + this.VirtualPrinter.SetNextElementFieldData(new UpcExtensionBarcodeFieldData + { + FieldOrientation = fieldOrientation, + Height = height, + PrintInterpretationLine = printInterpretationLine, + PrintInterpretationLineAboveCode = printInterpretationLineAboveCode + }); + + return null; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ZplCommandAnalyzerBase.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ZplCommandAnalyzerBase.cs index 6ad19467..2f742cd0 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ZplCommandAnalyzerBase.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/ZplCommandAnalyzerBase.cs @@ -26,7 +26,7 @@ public bool CanAnalyze(string zplLine) protected string[] SplitCommand(string zplCommand, int dataStartIndex = 0) { string zplCommandData = zplCommand.Substring(this.PrinterCommandPrefix.Length + dataStartIndex); - return zplCommandData.TrimStart().Split(','); + return zplCommandData.Trim().Split(','); } protected FieldOrientation ConvertFieldOrientation(string fieldOrientation) @@ -37,7 +37,32 @@ protected FieldOrientation ConvertFieldOrientation(string fieldOrientation) "R" => FieldOrientation.Rotated90, "I" => FieldOrientation.Rotated180, "B" => FieldOrientation.Rotated270, - _ => this.VirtualPrinter.FieldOrientation, + _ => this.VirtualPrinter.FieldOrientation, + }; + } + + protected QualityLevel ConvertQualityLevel(string qualityLevel) + { + return qualityLevel switch + { + "0" => QualityLevel.ECC0, + "50" => QualityLevel.ECC50, + "80" => QualityLevel.ECC80, + "100" => QualityLevel.ECC100, + "140" => QualityLevel.ECC140, + "200" => QualityLevel.ECC200, + _ => QualityLevel.ECC0 + }; + } + + protected FieldJustification ConvertFieldJustification(string fieldJustification) + { + return fieldJustification switch + { + "0" => FieldJustification.Left, + "1" => FieldJustification.Right, + "2" => FieldJustification.Auto, + _ => this.VirtualPrinter.FieldJustification, }; } @@ -49,7 +74,7 @@ protected ErrorCorrectionLevel ConvertErrorCorrectionLevel(string errorCorrectio "Q" => ErrorCorrectionLevel.HighReliability, "M" => ErrorCorrectionLevel.Standard, "L" => ErrorCorrectionLevel.HighDensity, - _ => ErrorCorrectionLevel.Standard, + _ => ErrorCorrectionLevel.Standard, }; } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/AztecBarcodeElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/AztecBarcodeElementDrawer.cs new file mode 100644 index 00000000..7ef7e95a --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/AztecBarcodeElementDrawer.cs @@ -0,0 +1,75 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + +using SkiaSharp; + +using ZXing.Aztec; +using ZXing.Common; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + public class AztecBarcodeElementDrawer : BarcodeDrawerBase + { + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplAztecBarcode; + } + + /// + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) + { + if (element is ZplAztecBarcode aztecBarcode) + { + float x = aztecBarcode.PositionX; + float y = aztecBarcode.PositionY; + + if (aztecBarcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = aztecBarcode.Content; + + if (aztecBarcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + AztecWriter writer = new(); + AztecEncodingOptions encodingOptions = new(); + if (aztecBarcode.ErrorControl >= 1 && aztecBarcode.ErrorControl <= 99) + { + encodingOptions.ErrorCorrection = aztecBarcode.ErrorControl; + } + else if (aztecBarcode.ErrorControl >= 101 && aztecBarcode.ErrorControl <= 104) + { + encodingOptions.Layers = 100 - aztecBarcode.ErrorControl; + } + else if (aztecBarcode.ErrorControl >= 201 && aztecBarcode.ErrorControl <= 232) + { + encodingOptions.Layers = aztecBarcode.ErrorControl - 200; + } + else if (aztecBarcode.ErrorControl == 300) + { + encodingOptions.PureBarcode = true; + } + else + { + // default options + } + + BitMatrix result = writer.encode(content, ZXing.BarcodeFormat.AZTEC, 0, 0, encodingOptions.Hints); + + using SKBitmap resizedImage = BitMatrixToSKBitmap(result, aztecBarcode.MagnificationFactor); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, aztecBarcode.FieldOrigin != null, aztecBarcode.FieldOrientation); + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, aztecBarcode.FieldOrigin != null, aztecBarcode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs index 503d8716..8f4ae722 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs @@ -1,6 +1,10 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; using BinaryKits.Zpl.Viewer.Symologies; + using SkiaSharp; + using System; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -17,11 +21,16 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplBarcode128 barcode) { string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + Code128CodeSet codeSet = Code128CodeSet.Code128B; bool gs1 = false; if (string.IsNullOrEmpty(barcode.Mode) || barcode.Mode == "N") @@ -46,26 +55,37 @@ public override void Draw(ZplElementBase element, DrawerOptions options) { checksum += (content[i] - 48) * (i % 2 * 2 + 7); } + content = $">8{content}{checksum % 10}"; } float x = barcode.PositionX; float y = barcode.PositionY; - var (data, interpretation) = ZplCode128Symbology.Encode(content, codeSet, gs1); - using var resizedImage = this.BoolArrayToSKBitmap(data.ToArray(), barcode.Height, barcode.ModuleWidth); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + (bool[] data, string interpretation) = ZplCode128Symbology.Encode(content, codeSet, gs1); + using SKBitmap resizedImage = BoolArrayToSKBitmap(data, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); if (barcode.PrintInterpretationLine) { // TODO: use font 0, auto scale for Mode D float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); - var labelTypeFace = options.FontLoader("A"); - var labelFont = new SKFont(labelTypeFace, labelFontSize); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); } + + return currentPosition; } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode39ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode39ElementDrawer.cs index dab0a022..8b84014f 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode39ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode39ElementDrawer.cs @@ -1,6 +1,11 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; + using ZXing.OneD; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -17,33 +22,48 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplBarcode39 barcode) { float x = barcode.PositionX; float y = barcode.PositionY; - var content = barcode.Content.Trim('*'); - var interpretation = string.Format("*{0}*", content); + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } - var writer = new Code39Writer(); - var result = writer.encode(content); + string content = barcode.Content.Trim('*'); + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + string interpretation = string.Format("*{0}*", content); + + Code39Writer writer = new(); + bool[] result = writer.encode(content); int narrow = barcode.ModuleWidth; int wide = (int)Math.Floor(barcode.WideBarToNarrowBarWidthRatio * narrow); - result = this.AdjustWidths(result, wide, narrow); - using var resizedImage = this.BoolArrayToSKBitmap(result, barcode.Height); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + result = AdjustWidths(result, wide, narrow); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); if (barcode.PrintInterpretationLine) { float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); - var labelTypeFace = options.FontLoader("A"); - var labelFont = new SKFont(labelTypeFace, labelFontSize); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs index ae4f951c..aa9b3b16 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs @@ -1,6 +1,11 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; + using ZXing.OneD; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -14,36 +19,43 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) - { - Draw(element, new DrawerOptions()); - } - - /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplBarcode93 barcode) { float x = barcode.PositionX; float y = barcode.PositionY; - var content = barcode.Content; + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } - var writer = new Code93Writer(); - var result = writer.encode(content); - using var resizedImage = this.BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + Code93Writer writer = new(); + bool[] result = writer.encode(content); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); if (barcode.PrintInterpretationLine) { float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); - var labelTypeFace = options.FontLoader("A"); - var labelFont = new SKFont(labelTypeFace, labelFontSize); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); this.DrawInterpretationLine(content, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); } + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeAnsiCodabarElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeAnsiCodabarElementDrawer.cs new file mode 100644 index 00000000..00ab0165 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeAnsiCodabarElementDrawer.cs @@ -0,0 +1,69 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + +using SkiaSharp; + +using System; + +using ZXing.OneD; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + /// + /// Drawer for Code 39 Barcode elements + /// + public class BarcodeAnsiCodabarElementDrawer : BarcodeDrawerBase + { + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplBarcodeAnsiCodabar; + } + + /// + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) + { + if (element is ZplBarcodeAnsiCodabar barcode) + { + float x = barcode.PositionX; + float y = barcode.PositionY; + + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content.Trim('*'); + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + string interpretation = string.Format("*{0}*", content); + + CodaBarWriter writer = new(); + bool[] result = writer.encode(content); + int narrow = barcode.ModuleWidth; + int wide = (int)Math.Floor(barcode.WideBarToNarrowBarWidthRatio * narrow); + result = AdjustWidths(result, wide, narrow); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); + + if (barcode.PrintInterpretationLine) + { + float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); + this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); + } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeDrawerBase.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeDrawerBase.cs index eead6e13..3c6061dc 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeDrawerBase.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeDrawerBase.cs @@ -1,8 +1,10 @@ using SkiaSharp; using SkiaSharp.HarfBuzz; + using System; using System.Collections.Generic; using System.Linq; + using ZXing.Common; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -17,83 +19,71 @@ public abstract class BarcodeDrawerBase : ElementDrawerBase /// protected const float MIN_LABEL_MARGIN = 5f; - protected void DrawBarcode( - byte[] barcodeImageData, - float x, - float y, - int barcodeWidth, - int barcodeHeight, - bool useFieldOrigin, - Label.FieldOrientation fieldOrientation) + protected void DrawBarcode(byte[] barcodeImageData, float x, float y, int barcodeWidth, int barcodeHeight, bool useFieldOrigin, Label.FieldOrientation fieldOrientation) { - using (new SKAutoCanvasRestore(this._skCanvas)) + using (new SKAutoCanvasRestore(this.skCanvas)) { - SKMatrix matrix = this.GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); - + SKMatrix matrix = GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); if (!useFieldOrigin) { y -= barcodeHeight; + if (y < 0) + { + y = 0; + } } if (matrix != SKMatrix.Empty) { - this._skCanvas.SetMatrix(matrix); + this.skCanvas.Concat(matrix); } - this._skCanvas.DrawBitmap(SKBitmap.Decode(barcodeImageData), x, y); + this.skCanvas.DrawBitmap(SKBitmap.Decode(barcodeImageData), x, y); } } - protected void DrawInterpretationLine( - string interpretation, - SKFont skFont, - float x, - float y, - int barcodeWidth, - int barcodeHeight, - bool useFieldOrigin, - Label.FieldOrientation fieldOrientation, - bool printInterpretationLineAboveCode, - DrawerOptions options) + protected void DrawInterpretationLine(string interpretation, SKFont skFont, float x, float y, int barcodeWidth, int barcodeHeight, bool useFieldOrigin, Label.FieldOrientation fieldOrientation, bool printInterpretationLineAboveCode, DrawerOptions options) { - using (new SKAutoCanvasRestore(this._skCanvas)) + using (new SKAutoCanvasRestore(this.skCanvas)) { - using var skPaint = new SKPaint(skFont); - skPaint.IsAntialias = options.Antialias; - - SKMatrix matrix = this.GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); + using SKPaint skPaint = new() + { + IsAntialias = options.Antialias + }; + SKMatrix matrix = GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); if (matrix != SKMatrix.Empty) { - this._skCanvas.SetMatrix(matrix); + this.skCanvas.Concat(matrix); } - var textBounds = new SKRect(); - skPaint.MeasureText(interpretation, ref textBounds); - + skFont.MeasureText(interpretation, out SKRect textBounds); x += (barcodeWidth - textBounds.Width) / 2; if (!useFieldOrigin) { y -= barcodeHeight; + if (y < 0) + { + y = 0; + } } float margin = Math.Max((skFont.Spacing - textBounds.Height) / 2, MIN_LABEL_MARGIN); - if (printInterpretationLineAboveCode) { - this._skCanvas.DrawShapedText(interpretation, x, y - margin, skPaint); + this.skCanvas.DrawShapedText(interpretation, x, y - margin, skFont, skPaint); } else { - this._skCanvas.DrawShapedText(interpretation, x, y + barcodeHeight + textBounds.Height + margin, skPaint); + this.skCanvas + .DrawShapedText(interpretation, x, y + barcodeHeight + textBounds.Height + margin, skFont, skPaint); } } } - protected SKMatrix GetRotationMatrix(float x, float y, int width, int height, bool useFieldOrigin, Label.FieldOrientation fieldOrientation) + protected static SKMatrix GetRotationMatrix(float x, float y, int width, int height, bool useFieldOrigin, Label.FieldOrientation fieldOrientation) { SKMatrix matrix = SKMatrix.Empty; - if (useFieldOrigin) { switch (fieldOrientation) @@ -132,45 +122,58 @@ protected SKMatrix GetRotationMatrix(float x, float y, int width, int height, bo return matrix; } - protected SKBitmap BoolArrayToSKBitmap(bool[] array, int height, int moduleWidth = 1) + protected static SKBitmap BoolArrayToSKBitmap(bool[] array, int height, int moduleWidth = 1) { - using var image = new SKBitmap(array.Length, 1); - + using SKBitmap image = new(array.Length, 1); for (int col = 0; col < array.Length; col++) { - var color = array[col] ? SKColors.Black : SKColors.Transparent; + SKColor color = array[col] ? SKColors.Black : SKColors.Transparent; image.SetPixel(col, 0, color); } - return image.Resize(new SKSizeI(image.Width * moduleWidth, height), SKFilterQuality.None); + SKSamplingOptions sampling = new(SKFilterMode.Nearest); + return image.Resize(new SKSizeI(image.Width * moduleWidth, height), sampling); } - protected SKBitmap BitMatrixToSKBitmap(BitMatrix matrix, int pixelScale) + protected static SKBitmap BoolArrayWithMaskToSKBitmap(bool[] array, bool[] mask, int height, int moduleWidth = 1) { - using var image = new SKBitmap(matrix.Width, matrix.Height); + using SKBitmap image = new(array.Length, 1); + for (int col = 0; col < array.Length; col++) + { + SKColor color = array[col] && mask[col] ? SKColors.Black : SKColors.Transparent; + image.SetPixel(col, 0, color); + } + SKSamplingOptions sampling = new(SKFilterMode.Nearest); + return image.Resize(new SKSizeI(image.Width * moduleWidth, height), sampling); + } + + protected static SKBitmap BitMatrixToSKBitmap(BitMatrix matrix, int pixelScale) + { + using SKBitmap image = new(matrix.Width, matrix.Height); for (int row = 0; row < matrix.Height; row++) { for (int col = 0; col < matrix.Width; col++) { - var color = matrix[col, row] ? SKColors.Black : SKColors.Transparent; + SKColor color = matrix[col, row] ? SKColors.Black : SKColors.Transparent; image.SetPixel(col, row, color); } } - return image.Resize(new SKSizeI(image.Width * pixelScale, image.Height * pixelScale), SKFilterQuality.None); + SKSamplingOptions sampling = new(SKFilterMode.Nearest); + return image.Resize(new SKSizeI(image.Width * pixelScale, image.Height * pixelScale), sampling); } - protected bool[] AdjustWidths(bool[] array, int wide, int narrow) + protected static bool[] AdjustWidths(bool[] array, int wide, int narrow) { - List result = new List(); - var last = true; - var count = 0; - foreach (var current in array) + List result = []; + bool last = true; + int count = 0; + foreach (bool current in array) { if (current != last) { - result.AddRange(Enumerable.Repeat(last, count == 1 ? narrow : wide)); + result.AddRange(Enumerable.Repeat(last, count == 1 ? narrow : wide)); last = current; count = 0; } @@ -178,8 +181,7 @@ protected bool[] AdjustWidths(bool[] array, int wide, int narrow) count += 1; } - result.AddRange(Enumerable.Repeat(last, narrow)); - + result.AddRange(Enumerable.Repeat(last, narrow)); return result.ToArray(); } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeEAN13ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeEAN13ElementDrawer.cs index c0ca0b1f..8e97d61e 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeEAN13ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeEAN13ElementDrawer.cs @@ -1,6 +1,11 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; + using ZXing.OneD; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -27,35 +32,47 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplBarcodeEan13 barcode) { float x = barcode.PositionX; float y = barcode.PositionY; - var content = barcode.Content; + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + content = content.PadLeft(12, '0').Substring(0, 12); - var interpretation = content; + string interpretation = content; int checksum = 0; for (int i = 0; i < 12; i++) { checksum += (content[i] - 48) * (9 - i % 2 * 2); } + interpretation = string.Format("{0}{1}", interpretation, checksum % 10); - var writer = new EAN13Writer(); - var result = writer.encode(content); - using var resizedImage = this.BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + EAN13Writer writer = new(); + bool[] result = writer.encode(content); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); if (barcode.PrintInterpretationLine) { float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); - var labelTypeFace = options.FontLoader("A"); - var labelFont = new SKFont(labelTypeFace, labelFontSize); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); if (barcode.PrintInterpretationLineAboveCode) { this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, true, options); @@ -66,7 +83,10 @@ public override void Draw(ZplElementBase element, DrawerOptions options) } } + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); } + + return currentPosition; } private void DrawEAN13InterpretationLine( @@ -77,43 +97,49 @@ private void DrawEAN13InterpretationLine( int barcodeWidth, int barcodeHeight, bool useFieldOrigin, - Label.FieldOrientation fieldOrientation, + FieldOrientation fieldOrientation, int moduleWidth, DrawerOptions options) { - using (new SKAutoCanvasRestore(this._skCanvas)) + using (new SKAutoCanvasRestore(this.skCanvas)) { - using var skPaint = new SKPaint(skFont); - skPaint.IsAntialias = options.Antialias; + using SKPaint skPaint = new() + { + IsAntialias = options.Antialias + }; - SKMatrix matrix = this.GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); + SKMatrix matrix = GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); if (matrix != SKMatrix.Empty) { - this._skCanvas.SetMatrix(matrix); + SKMatrix currentMatrix = this.skCanvas.TotalMatrix; + SKMatrix concatMatrix = SKMatrix.Concat(currentMatrix, matrix); + this.skCanvas.SetMatrix(concatMatrix); } - var textBounds = new SKRect(); - skPaint.MeasureText(interpretation, ref textBounds); + skFont.MeasureText(interpretation, out SKRect textBounds); if (!useFieldOrigin) { y -= barcodeHeight; + if (y < 0) + { + y = 0; + } } float margin = Math.Max((skFont.Spacing - textBounds.Height) / 2, MIN_LABEL_MARGIN); int spacing = moduleWidth * 7; - using var guardImage = this.BoolArrayToSKBitmap(guards, (int)(margin + textBounds.Height / 2), moduleWidth); - var guardPng = guardImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); - this._skCanvas.DrawBitmap(SKBitmap.Decode(guardPng), x, y + barcodeHeight); + using SKBitmap guardImage = BoolArrayToSKBitmap(guards, (int)(margin + textBounds.Height / 2), moduleWidth); + byte[] guardPng = guardImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.skCanvas.DrawBitmap(SKBitmap.Decode(guardPng), x, y + barcodeHeight); for (int i = 0; i < interpretation.Length; i++) { string digit = interpretation[i].ToString(); - var digitBounds = new SKRect(); - skPaint.MeasureText(digit, ref digitBounds); - this._skCanvas.DrawText(digit, x - (spacing + digitBounds.Width) / 2 - moduleWidth, y + barcodeHeight + textBounds.Height + margin, skPaint); + skFont.MeasureText(digit, out SKRect digitBounds); + this.skCanvas.DrawText(digit, x - (spacing + digitBounds.Width) / 2 - moduleWidth, y + barcodeHeight + textBounds.Height + margin, skFont, skPaint); x += spacing; if (i == 0 || i == 6) { diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcAElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcAElementDrawer.cs new file mode 100644 index 00000000..0b7849ee --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcAElementDrawer.cs @@ -0,0 +1,168 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + +using SkiaSharp; + +using System; + +using ZXing.OneD; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + public class BarcodeUpcAElementDrawer : BarcodeDrawerBase + { + private static readonly bool[] guards = new bool[95]; + + static BarcodeUpcAElementDrawer() + { + int[] guardIndicies = [ + 0, 2, + 4, 5, 6, 7, 8, 9, + 46, 48, + 85, 86, 87, 88, 89, 90, + 92, 94 + ]; + + foreach (int idx in guardIndicies) + { + guards[idx] = true; + } + } + + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplBarcodeUpcA; + } + + /// + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) + { + if (element is ZplBarcodeUpcA barcode) + { + float x = barcode.PositionX; + float y = barcode.PositionY; + + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + content = content.PadLeft(11, '0').Substring(0, 11); + string interpretation = content; + + if (barcode.PrintCheckDigit) + { + int checksum = 0; + for (int i = 0; i < 11; i++) + { + checksum += (content[i] - 48) * (i % 2 * 2 + 7); + } + + interpretation = string.Format("{0}{1}", interpretation, checksum % 10); + } + + + EAN13Writer writer = new(); + bool[] result = writer.encode(content.PadLeft(12, '0')); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); + + if (barcode.PrintInterpretationLine) + { + float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); + if (barcode.PrintInterpretationLineAboveCode) + { + this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, true, options); + } + else + { + this.DrawUpcAInterpretationLine(result, interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.ModuleWidth, options); + } + } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + + private void DrawUpcAInterpretationLine( + bool[] data, + string interpretation, + SKFont skFont, + float x, + float y, + int barcodeWidth, + int barcodeHeight, + bool useFieldOrigin, + FieldOrientation fieldOrientation, + int moduleWidth, + DrawerOptions options) + { + using (new SKAutoCanvasRestore(this.skCanvas)) + { + using SKPaint skPaint = new() + { + IsAntialias = options.Antialias + }; + + SKMatrix matrix = GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); + + if (matrix != SKMatrix.Empty) + { + SKMatrix currentMatrix = this.skCanvas.TotalMatrix; + SKMatrix concatMatrix = SKMatrix.Concat(currentMatrix, matrix); + this.skCanvas.SetMatrix(concatMatrix); + } + + skFont.MeasureText(interpretation, out SKRect textBounds); + + if (!useFieldOrigin) + { + y -= barcodeHeight; + if (y < 0) + { + y = 0; + } + } + + float margin = Math.Max((skFont.Spacing - textBounds.Height) / 2, MIN_LABEL_MARGIN); + int spacing = moduleWidth * 7; + + using SKBitmap guardImage = BoolArrayWithMaskToSKBitmap(data, guards, (int)(margin + textBounds.Height / 2), moduleWidth); + byte[] guardPng = guardImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.skCanvas.DrawBitmap(SKBitmap.Decode(guardPng), x, y + barcodeHeight); + + for (int i = 0; i < interpretation.Length; i++) + { + string digit = interpretation[i].ToString(); + skFont.MeasureText(digit, out SKRect digitBounds); + this.skCanvas.DrawText(digit, x - (spacing + digitBounds.Width) / 2 - moduleWidth, y + barcodeHeight + textBounds.Height + margin, skFont, skPaint); + x += spacing; + + if (i == 0 || i == 10) + { + x += moduleWidth * 11; + } + else if (i == 5) + { + x += moduleWidth * 4; + } + } + } + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcEElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcEElementDrawer.cs new file mode 100644 index 00000000..5182a56d --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcEElementDrawer.cs @@ -0,0 +1,206 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + +using SkiaSharp; + +using System; + +using ZXing.OneD; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + public class BarcodeUpcEElementDrawer : BarcodeDrawerBase + { + private static readonly bool[] guards = new bool[51]; + + static BarcodeUpcEElementDrawer() + { + foreach (int idx in new int[] { 0, 2, 46, 48, 50 }) + { + guards[idx] = true; + } + } + + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplBarcodeUpcE; + } + + /// + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) + { + if (element is ZplBarcodeUpcE barcode) + { + float x = barcode.PositionX; + float y = barcode.PositionY; + + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + // [S]DDDDDD[C] + if (content.Length < 7) + { + // number system 0 + content = content.PadLeft(7, '0'); + } + else if (content.Length <= 8) + { + // ignore user provided checksum + content = content.Substring(0, 7); + } + else + { + // UPC-A to UPC-E + string numberSystem = "0"; + content = content.PadRight(10, '0'); + if (content.Length > 10) + { + numberSystem = content.Substring(0, 1); + content = content.Substring(1, 10); + } + + int manufacturer = int.Parse(content.Substring(0, 5)); + int product = int.Parse(content.Substring(5, 5)); + + if (manufacturer % 100 == 0) + { + int trail = manufacturer / 100 % 10; + if (trail <= 2) + { + content = $"{numberSystem}{manufacturer / 1000:D2}{product % 1000:D3}{trail}"; + } + else + { + content = $"{numberSystem}{manufacturer / 100:D3}{product % 100:D2}{3}"; + } + } + else if (manufacturer % 10 == 0) + { + content = $"{numberSystem}{manufacturer / 10:D4}{product % 10:D1}{4}"; + } + else + { + content = $"{numberSystem}{manufacturer:D5}{Math.Max(product % 10, 5):D1}"; + } + } + + string interpretation = content; + + if (barcode.PrintCheckDigit) + { + string expanded = UPCEReader.convertUPCEtoUPCA(content); + int checksum = 0; + for (int i = 0; i < 11; i++) + { + checksum += (expanded[i] - 48) * (i % 2 * 2 + 7); + } + + interpretation = string.Format("{0}{1}", interpretation, checksum % 10); + } + + UPCEWriter writer = new(); + bool[] result = writer.encode(content); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); + + if (barcode.PrintInterpretationLine) + { + float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); + if (barcode.PrintInterpretationLineAboveCode) + { + this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, true, options); + } + else + { + this.DrawUpcEInterpretationLine(result, interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.ModuleWidth, options); + } + } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + + private void DrawUpcEInterpretationLine( + bool[] data, + string interpretation, + SKFont skFont, + float x, + float y, + int barcodeWidth, + int barcodeHeight, + bool useFieldOrigin, + FieldOrientation fieldOrientation, + int moduleWidth, + DrawerOptions options) + { + using (new SKAutoCanvasRestore(this.skCanvas)) + { + using SKPaint skPaint = new() + { + IsAntialias = options.Antialias + }; + + SKMatrix matrix = GetRotationMatrix(x, y, barcodeWidth, barcodeHeight, useFieldOrigin, fieldOrientation); + + if (matrix != SKMatrix.Empty) + { + SKMatrix currentMatrix = this.skCanvas.TotalMatrix; + SKMatrix concatMatrix = SKMatrix.Concat(currentMatrix, matrix); + this.skCanvas.SetMatrix(concatMatrix); + } + + skFont.MeasureText(interpretation, out SKRect textBounds); + + if (!useFieldOrigin) + { + y -= barcodeHeight; + if (y < 0) + { + y = 0; + } + } + + float margin = Math.Max((skFont.Spacing - textBounds.Height) / 2, MIN_LABEL_MARGIN); + int spacing = moduleWidth * 7; + + using SKBitmap guardImage = BoolArrayToSKBitmap(guards, (int)(margin + textBounds.Height / 2), moduleWidth); + byte[] guardPng = guardImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.skCanvas.DrawBitmap(SKBitmap.Decode(guardPng), x, y + barcodeHeight); + + for (int i = 0; i < interpretation.Length; i++) + { + string digit = interpretation[i].ToString(); + skFont.MeasureText(digit, out SKRect digitBounds); + this.skCanvas.DrawText(digit, x - (spacing + digitBounds.Width) / 2 - moduleWidth, y + barcodeHeight + textBounds.Height + margin, skFont, skPaint); + x += spacing; + + if (i == 0) + { + x += moduleWidth * 4; + } + else if (i == 6) + { + x += moduleWidth * 6; + } + } + } + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcExtensionElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcExtensionElementDrawer.cs new file mode 100644 index 00000000..3b38791b --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/BarcodeUpcExtensionElementDrawer.cs @@ -0,0 +1,76 @@ +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; +using BinaryKits.Zpl.Viewer.Symologies; + +using SkiaSharp; + +using System; + +using ZXing.Common; +using ZXing.OneD; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + public class BarcodeUpcExtensionElementDrawer : BarcodeDrawerBase + { + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplBarcodeUpcExtension; + } + + /// + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) + { + if (element is ZplBarcodeUpcExtension barcode) + { + float x = barcode.PositionX; + float y = barcode.PositionY; + + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + if (content.Length <= 2) + { + // EAN-2 + content = content.PadLeft(2, '0'); + } + else + { + // EAN-5 + content = content.PadLeft(5, '0').Substring(0, 5); + } + + string interpretation = content; + + bool[] data= UpcExtensionSymbology.Encode(content); + using SKBitmap resizedImage = BoolArrayToSKBitmap(data, barcode.Height, barcode.ModuleWidth); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); + + if (barcode.PrintInterpretationLine) + { + float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); + this.DrawInterpretationLine(interpretation, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); + } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs index fc6f70a5..6f60180b 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs @@ -1,7 +1,13 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System.Text.RegularExpressions; + using ZXing; +using ZXing.Common; using ZXing.Datamatrix; using ZXing.Datamatrix.Encoder; @@ -12,7 +18,7 @@ namespace BinaryKits.Zpl.Viewer.ElementDrawers /// public class DataMatrixElementDrawer : BarcodeDrawerBase { - private static readonly Regex gs1Regex = new Regex(@"^_1(.+)$", RegexOptions.Compiled); + private static readonly Regex gs1Regex = new(@"^_1(.+)$", RegexOptions.Compiled); /// public override bool CanDraw(ZplElementBase element) @@ -21,23 +27,37 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplDataMatrix dataMatrix) { if (dataMatrix.Height == 0) + { throw new System.Exception("Matrix Height is set to zero."); + } if (string.IsNullOrWhiteSpace(dataMatrix.Content)) + { throw new System.Exception("Matrix Content is empty."); + } float x = dataMatrix.PositionX; float y = dataMatrix.PositionY; + if (dataMatrix.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = dataMatrix.Content; + if (dataMatrix.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + // support hand-rolled GS1 bool gs1Mode = false; - var content = dataMatrix.Content; - Match gs1Match = gs1Regex.Match(content); if (gs1Match.Success) { @@ -45,22 +65,25 @@ public override void Draw(ZplElementBase element) gs1Mode = true; } - var writer = new DataMatrixWriter(); - var encodingOptions = new DatamatrixEncodingOptions() + DataMatrixWriter writer = new(); + DatamatrixEncodingOptions encodingOptions = new() { SymbolShape = SymbolShapeHint.FORCE_SQUARE, CompactEncoding = gs1Mode, GS1Format = gs1Mode }; - var result = writer.encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, encodingOptions.Hints); + BitMatrix result = writer.encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, encodingOptions.Hints); - using var resizedImage = this.BitMatrixToSKBitmap(result, dataMatrix.Height); + using SKBitmap resizedImage = BitMatrixToSKBitmap(result, dataMatrix.Height); { - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, dataMatrix.FieldOrigin != null, dataMatrix.FieldOrientation); } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, dataMatrix.FieldOrigin != null, dataMatrix.FieldOrientation, currentPosition); } - } + return currentPosition; + } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DrawerOptions.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DrawerOptions.cs index ad2f5245..fb5638fb 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DrawerOptions.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DrawerOptions.cs @@ -1,13 +1,14 @@ using SkiaSharp; + using System; -using System.Diagnostics; +using System.Collections.Generic; using System.Linq; namespace BinaryKits.Zpl.Viewer.ElementDrawers { public class DrawerOptions { - public Func FontLoader { get; set; } = DefaultFontLoader; + public Func FontLoader { get; set; } = defaultFontLoader; public SKEncodedImageFormat RenderFormat { get; set; } = SKEncodedImageFormat.Png; @@ -17,112 +18,90 @@ public class DrawerOptions /// Applies label over a white background after rendering all elements /// public bool OpaqueBackground { get; set; } = false; - + /// /// Renders the label as pdf /// public bool PdfOutput { get; set; } = false; + /// + /// Gets or sets a value indicating whether dashes should be replaced with en dash. + /// public bool ReplaceDashWithEnDash { get; set; } = true; + /// + /// Gets or sets a value indicating whether underscores in text should be replaced with en space. + /// + public bool ReplaceUnderscoreWithEnSpace { get; set; } = false; + + /// + /// Gets or sets a value indicating whether antialiasing is enabled. + /// public bool Antialias { get; set; } = true; - public static Func DefaultFontLoader = fontName => { - var typeface = SKTypeface.Default; - var skFontManager = SKFontManager.Default; - var fontFamilies = skFontManager.FontFamilies; - - if (fontName == "0") + private static readonly string[] fontStack0 = [ + "Swis721 Cn BT", + "Nimbus Sans", + "Arial", + "Helvetica Neue", + "Roboto Condensed" + ]; + + private static readonly string[] fontStackA = [ + "DejaVu Sans Mono", + "Cascadia Code", + "Consolas", + "SF Mono", + "Droid Sans Mono" + ]; + + private static readonly SKTypeface typeface0; + private static readonly SKTypeface typefaceA; + + static DrawerOptions() + { + SKFontManager skFontManager = SKFontManager.Default; + IEnumerable fontFamilies = skFontManager.FontFamilies; + + typeface0 = SKTypeface.Default; + typefaceA = SKTypeface.Default; + + foreach (string familyName in fontStack0) { - if (fontFamilies.Contains("Helvetica")) - { - typeface = SKTypeface.FromFamilyName( - "Helvetica", - SKFontStyleWeight.Bold, - SKFontStyleWidth.SemiCondensed, - SKFontStyleSlant.Upright - ); - } - else if (fontFamilies.Contains("Roboto Condensed")) - { - typeface = SKTypeface.FromFamilyName( - "Roboto Condensed", - SKFontStyleWeight.Bold, - SKFontStyleWidth.Normal, - SKFontStyleSlant.Upright - ); - } - else if (fontFamilies.Contains("Swis721 BT")) - { - //Note: Zebra Swis721 BT (tt0003m_.ttf) is not as bold and condensed as Labelary - //Note: swiss-721-bt-bold.ttf is not as condensed as Labelary - //typeface = SKTypeface.FromFile(@"swiss-721-black-bt.ttf"); - typeface = SKTypeface.FromFamilyName( - "Swis721 BT" - ); - } - else if (fontFamilies.Contains("Arial")) - { - typeface = SKTypeface.FromFamilyName( - "Arial", - SKFontStyleWeight.Bold, - SKFontStyleWidth.Condensed, - SKFontStyleSlant.Upright - ); - } - else + if (fontFamilies.Contains(familyName)) { - //let the system provide a fallback for Helvetica - typeface = SKTypeface.FromFamilyName( - "Helvetica", + typeface0 = SKTypeface.FromFamilyName( + familyName, SKFontStyleWeight.Bold, SKFontStyleWidth.SemiCondensed, SKFontStyleSlant.Upright ); + break; } } - else + + foreach (string familyName in fontStackA) { - if (fontFamilies.Contains("DejaVu Sans Mono")) - { - typeface = SKTypeface.FromFamilyName( - "DejaVu Sans Mono", - SKFontStyleWeight.Normal, - SKFontStyleWidth.Normal, - SKFontStyleSlant.Upright - ); - } - else if (fontFamilies.Contains("Courier New")) + if (fontFamilies.Contains(familyName)) { - typeface = SKTypeface.FromFamilyName( - "Courier New", - SKFontStyleWeight.Medium, - SKFontStyleWidth.Normal, - SKFontStyleSlant.Upright - ); - } - else if (fontFamilies.Contains("Courier")) - { - typeface = SKTypeface.FromFamilyName( - "Courier", - SKFontStyleWeight.Medium, - SKFontStyleWidth.Normal, - SKFontStyleSlant.Upright - ); - } - else - { - //let the system provide a fallback for DejaVu - typeface = SKTypeface.FromFamilyName( - "DejaVu Sans Mono", + typefaceA = SKTypeface.FromFamilyName( + familyName, SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright ); + break; } } + } + + private static readonly Func defaultFontLoader = fontName => { + if (fontName == "0") + { + return typeface0; + } - return typeface; + return typefaceA; }; } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/ElementDrawerBase.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/ElementDrawerBase.cs index 3947c232..0a7c4b56 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/ElementDrawerBase.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/ElementDrawerBase.cs @@ -1,20 +1,22 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers { public abstract class ElementDrawerBase : IElementDrawer { - internal IPrinterStorage _printerStorage; - internal SKCanvas _skCanvas; + internal IPrinterStorage printerStorage; + internal SKCanvas skCanvas; /// public void Prepare( IPrinterStorage printerStorage, SKCanvas skCanvas) { - this._printerStorage = printerStorage; - this._skCanvas = skCanvas; + this.printerStorage = printerStorage; + this.skCanvas = skCanvas; } /// @@ -25,13 +27,13 @@ public virtual bool IsReverseDraw(ZplElementBase element) { return false; } - + /// public virtual bool IsWhiteDraw(ZplElementBase element) { return false; } - + /// public virtual bool ForceBitmapDraw(ZplElementBase element) { @@ -39,15 +41,56 @@ public virtual bool ForceBitmapDraw(ZplElementBase element) } /// - public virtual void Draw(ZplElementBase element) + public virtual SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition) + { + return currentPosition; + } + + /// + public virtual SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { - Draw(element, new DrawerOptions()); + return this.Draw(element, options, currentPosition); } /// - public virtual void Draw(ZplElementBase element, DrawerOptions options = null) + public virtual SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont, int printDensityDpmm) + { + return this.Draw(element, options, currentPosition, internationalFont); + } + + protected virtual SKPoint CalculateNextDefaultPosition(float x, float y, float elementWidth, float elementHeight, bool useFieldOrigin, Label.FieldOrientation fieldOrientation, SKPoint currentPosition) { - Draw(element); // Most element just ignore the context + if (useFieldOrigin) + { + switch (fieldOrientation) + { + case Label.FieldOrientation.Normal: + return new SKPoint(x + elementWidth, y + elementHeight); + case Label.FieldOrientation.Rotated90: + return new SKPoint(x, y + elementHeight); + case Label.FieldOrientation.Rotated180: + return new SKPoint(x - elementWidth, y); + case Label.FieldOrientation.Rotated270: + return new SKPoint(x, y - elementHeight); + } + } + else + { + switch (fieldOrientation) + { + case Label.FieldOrientation.Normal: + return new SKPoint(x + elementWidth, y); + case Label.FieldOrientation.Rotated90: + return new SKPoint(x, y + elementWidth); + case Label.FieldOrientation.Rotated180: + return new SKPoint(x - elementWidth, y); + case Label.FieldOrientation.Rotated270: + return new SKPoint(x, y - elementWidth); + } + } + + return currentPosition; } + } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/FieldBlockElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/FieldBlockElementDrawer.cs index 5e59cdb9..e1d505ec 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/FieldBlockElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/FieldBlockElementDrawer.cs @@ -35,24 +35,24 @@ public override bool IsReverseDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplFieldBlock fieldBlock) { - var font = fieldBlock.Font; + ZplFont font = fieldBlock.Font; float fontSize = font.FontHeight > 0 ? font.FontHeight : font.FontWidth; - var scaleX = 1.00f; + float scaleX = 1.00f; if (font.FontWidth != 0 && font.FontWidth != fontSize) { scaleX *= (float)font.FontWidth / fontSize; } - var typeface = options.FontLoader(font.FontName); - var text = fieldBlock.Text; - if (fieldBlock.UseHexadecimalIndicator) + SKTypeface typeface = options.FontLoader(font.FontName); + string text = fieldBlock.Text; + if (fieldBlock.HexadecimalIndicator is char hexIndicator) { - text = text.ReplaceHexEscapes(); + text = text.ReplaceHexEscapes(hexIndicator, internationalFont); } if (options.ReplaceDashWithEnDash) @@ -60,24 +60,34 @@ public override void Draw(ZplElementBase element, DrawerOptions options) text = text.Replace("-", " \u2013 "); } - var skFont = new SKFont(typeface, fontSize, scaleX); - using var skPaint = new SKPaint(skFont) + if (options.ReplaceUnderscoreWithEnSpace) + { + text = text.Replace('_', '\u2002'); + } + + SKFont skFont = new(typeface, fontSize, scaleX); + using SKPaint skPaint = new() { IsAntialias = options.Antialias }; - var textBoundBaseline = new SKRect(); - skPaint.MeasureText("X", ref textBoundBaseline); + skFont.MeasureText("X", out SKRect textBoundBaseline); float x = fieldBlock.PositionX; float y = fieldBlock.PositionY + textBoundBaseline.Height; - var textLines = WordWrap(text, skFont, fieldBlock.Width); - var hangingIndent = 0; - var lineHeight = fontSize + fieldBlock.LineSpace; + if (fieldBlock.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y + textBoundBaseline.Height; + } + + IEnumerable textLines = WordWrap(text, skFont, fieldBlock.Width); + int hangingIndent = 0; + float lineHeight = fontSize + fieldBlock.LineSpace; // actual ZPL printer does not include trailing line spacing in total height - var totalHeight = lineHeight * fieldBlock.MaxLineCount - fieldBlock.LineSpace; + float totalHeight = lineHeight * fieldBlock.MaxLineCount - fieldBlock.LineSpace; // labelary //var totalHeight = lineHeight * fieldBlock.MaxLineCount; @@ -87,7 +97,7 @@ public override void Draw(ZplElementBase element, DrawerOptions options) y -= totalHeight; } - using (new SKAutoCanvasRestore(this._skCanvas)) + using (new SKAutoCanvasRestore(this.skCanvas)) { SKMatrix matrix = SKMatrix.Empty; @@ -128,16 +138,17 @@ public override void Draw(ZplElementBase element, DrawerOptions options) if (matrix != SKMatrix.Empty) { - this._skCanvas.SetMatrix(matrix); + SKMatrix currentMatrix = this.skCanvas.TotalMatrix; + SKMatrix concatMatrix = SKMatrix.Concat(currentMatrix, matrix); + this.skCanvas.SetMatrix(concatMatrix); } - foreach (var textLine in textLines) + foreach (string textLine in textLines) { x = fieldBlock.PositionX + hangingIndent; - var textBounds = new SKRect(); - skPaint.MeasureText(textLine, ref textBounds); - var diff = fieldBlock.Width - textBounds.Width; + skFont.MeasureText(textLine, out SKRect textBounds); + float diff = fieldBlock.Width - textBounds.Width; switch (fieldBlock.TextJustification) { @@ -160,31 +171,34 @@ public override void Draw(ZplElementBase element, DrawerOptions options) skPaint.BlendMode = SKBlendMode.Xor; } - this._skCanvas.DrawShapedText(textLine, x, y, skPaint); + this.skCanvas.DrawShapedText(textLine, x, y, skFont, skPaint); y += lineHeight; } + + return this.CalculateNextDefaultPosition(fieldBlock.PositionX, fieldBlock.PositionY, fieldBlock.Width, totalHeight, fieldBlock.FieldOrigin != null, fieldBlock.Font.FieldOrientation, currentPosition); } } + + return currentPosition; } - private IEnumerable WordWrap(string text, SKFont font, int maxWidth) + private static List WordWrap(string text, SKFont font, int maxWidth) { - using var tmpPaint = new SKPaint(font); - var spaceWidth = tmpPaint.MeasureText(" "); - var lines = new List(); + float spaceWidth = font.MeasureText(" "); + List lines = []; - var words = new Stack(text.Split(new[] { ' ' }, StringSplitOptions.None).Reverse()); - var line = new StringBuilder(); + Stack words = new(text.Split([' '], StringSplitOptions.None).Reverse()); + StringBuilder line = new(); float width = 0; - while (words.Any()) + while (words.Count != 0) { - var word = words.Pop(); + string word = words.Pop(); if (word.Contains(@"\&")) { - var subwords = word.Split(new[] { @"\&" }, 2, StringSplitOptions.None); + string[] subwords = word.Split([@"\&"], 2, StringSplitOptions.None); word = subwords[0]; words.Push(subwords[1]); - var wordWidth = tmpPaint.MeasureText(word); + float wordWidth = font.MeasureText(word); if (width + wordWidth <= maxWidth) { line.Append(word); @@ -198,6 +212,7 @@ private IEnumerable WordWrap(string text, SKFont font, int maxWidth) { lines.Add(line.ToString().Trim()); } + lines.Add(word.ToString()); line = new StringBuilder(); width = 0; @@ -205,7 +220,7 @@ private IEnumerable WordWrap(string text, SKFont font, int maxWidth) } else { - var wordWidth = tmpPaint.MeasureText(word); + float wordWidth = font.MeasureText(word); if (width + wordWidth <= maxWidth) { line.Append(word + " "); @@ -217,6 +232,7 @@ private IEnumerable WordWrap(string text, SKFont font, int maxWidth) { lines.Add(line.ToString().Trim()); } + line = new StringBuilder(word + " "); width = wordWidth + spaceWidth; } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicBoxElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicBoxElementDrawer.cs index 3a327c88..f67198a4 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicBoxElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicBoxElementDrawer.cs @@ -1,6 +1,8 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; + using System; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -44,13 +46,13 @@ public override bool ForceBitmapDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplGraphicBox graphicBox) { - var border1 = graphicBox.BorderThickness; - var width1 = graphicBox.Width; - var height1 = graphicBox.Height; + int border1 = graphicBox.BorderThickness; + int width1 = graphicBox.Width; + int height1 = graphicBox.Height; if (border1 > width1) { @@ -63,12 +65,12 @@ public override void Draw(ZplElementBase element, DrawerOptions options) } //border cant be bigger or equal to width or height - if (border1 > (width1 / 2) && width1 <= height1) + if (border1 > width1 / 2 && width1 <= height1) { border1 = (int)Math.Ceiling((float)width1 / 2); } - - if (border1 > (height1 / 2) && height1 <= width1) + + if (border1 > height1 / 2 && height1 <= width1) { border1 = (int)Math.Ceiling((float)height1 / 2); } @@ -79,23 +81,32 @@ public override void Draw(ZplElementBase element, DrawerOptions options) border1 = 1; } + float baseX = graphicBox.PositionX; + float baseY = graphicBox.PositionY; + + if (graphicBox.UseDefaultPosition) + { + baseX = currentPosition.X; + baseY = currentPosition.Y; + } + //if the border is thick, the rounding is off, so we need to build that for each increment - var lastPrintedBorder = border1; - for (var border2 = border1; border2 >= 1; border2--) + int lastPrintedBorder = border1; + for (int border2 = border1; border2 >= 1; border2--) { //skip the parts that have overlap from the previous draw - if (border2 != 1 && border2 != lastPrintedBorder && border2 > (lastPrintedBorder / 2)) + if (border2 != 1 && border2 != lastPrintedBorder && border2 > lastPrintedBorder / 2) { continue; } - + lastPrintedBorder = border2; - var offsetX = border2 / 2.0f; - var offsetY = border2 / 2.0f; + float offsetX = border2 / 2.0f; + float offsetY = border2 / 2.0f; - var x = graphicBox.PositionX + offsetX; - var y = graphicBox.PositionY + offsetY; + float x = baseX + offsetX; + float y = baseY + offsetY; if (graphicBox.FieldTypeset != null) { @@ -108,10 +119,10 @@ public override void Draw(ZplElementBase element, DrawerOptions options) } } - var width = width1 - border2; - var height = height1 - border2; + int width = width1 - border2; + int height = height1 - border2; - using var skPaint = new SKPaint() + using SKPaint skPaint = new() { IsAntialias = options.Antialias, Style = SKPaintStyle.Stroke, @@ -125,7 +136,7 @@ public override void Draw(ZplElementBase element, DrawerOptions options) skPaint.Color = SKColors.White; } - var cornerRadius = (graphicBox.CornerRounding / 8.0f) * (Math.Min(width1, height1) / 2.0f); + float cornerRadius = (graphicBox.CornerRounding / 8.0f) * (Math.Min(width1, height1) / 2.0f); if (cornerRadius == 0) { @@ -133,14 +144,20 @@ public override void Draw(ZplElementBase element, DrawerOptions options) { skPaint.BlendMode = SKBlendMode.Xor; } - - this._skCanvas.DrawRect(x, y, width, height, skPaint); - return; + + this.skCanvas.DrawRect(x, y, width, height, skPaint); + // Calculate next position based on box dimensions + return this.CalculateNextDefaultPosition(baseX, baseY, width1, height1, graphicBox.FieldOrigin != null, FieldOrientation.Normal, currentPosition); } - this._skCanvas.DrawRoundRect(x, y, width, height, cornerRadius, cornerRadius, skPaint); + this.skCanvas.DrawRoundRect(x, y, width, height, cornerRadius, cornerRadius, skPaint); } + + // Calculate next position based on box dimensions + return this.CalculateNextDefaultPosition(baseX, baseY, width1, height1, graphicBox.FieldOrigin != null, FieldOrientation.Normal, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicCircleElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicCircleElementDrawer.cs index 44498f44..6a94193d 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicCircleElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicCircleElementDrawer.cs @@ -1,5 +1,6 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -11,7 +12,7 @@ public override bool CanDraw(ZplElementBase element) { return element is ZplGraphicCircle; } - + public override bool IsReverseDraw(ZplElementBase element) { if (element is ZplGraphicCircle graphicCircle) @@ -21,7 +22,7 @@ public override bool IsReverseDraw(ZplElementBase element) return false; } - + public override bool IsWhiteDraw(ZplElementBase element) { if (element is ZplGraphicCircle graphicCircle) @@ -33,19 +34,19 @@ public override bool IsWhiteDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplGraphicCircle graphicCircle) { - var radius = graphicCircle.Diameter / 2.0f; - var border = (float)graphicCircle.BorderThickness; + float radius = graphicCircle.Diameter / 2.0f; + float border = graphicCircle.BorderThickness; if (border > radius) { border = radius; } - using var skPaint = new SKPaint() + using SKPaint skPaint = new() { IsAntialias = options.Antialias, Style = SKPaintStyle.Stroke, @@ -57,13 +58,22 @@ public override void Draw(ZplElementBase element, DrawerOptions options) skPaint.Color = SKColors.White; } - var halfBorderThickness = border / 2.0f; + float halfBorderThickness = border / 2.0f; - var radiusMinusBorder = radius - halfBorderThickness; - var offset = halfBorderThickness + radiusMinusBorder; + float radiusMinusBorder = radius - halfBorderThickness; + float offset = halfBorderThickness + radiusMinusBorder; - var x = graphicCircle.PositionX + offset; - var y = graphicCircle.PositionY + offset; + float baseX = graphicCircle.PositionX; + float baseY = graphicCircle.PositionY; + + if (graphicCircle.UseDefaultPosition) + { + baseX = currentPosition.X; + baseY = currentPosition.Y; + } + + float x = baseX + offset; + float y = baseY + offset; if (graphicCircle.FieldTypeset != null) { @@ -75,14 +85,17 @@ public override void Draw(ZplElementBase element, DrawerOptions options) y = radius; } } - + if (graphicCircle.ReversePrint) { skPaint.BlendMode = SKBlendMode.Xor; } - this._skCanvas.DrawCircle(x, y, radiusMinusBorder, skPaint); + this.skCanvas.DrawCircle(x, y, radiusMinusBorder, skPaint); + return this.CalculateNextDefaultPosition(baseX, baseY, graphicCircle.Diameter, graphicCircle.Diameter, graphicCircle.FieldOrigin != null, FieldOrientation.Normal, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicFieldElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicFieldElementDrawer.cs index dd98927c..b9f39aa8 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicFieldElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/GraphicFieldElementDrawer.cs @@ -1,5 +1,7 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Label.Helpers; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -16,24 +18,37 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplGraphicField graphicField) { - var imageData = ByteHelper.HexToBytes(graphicField.Data); - var image = SKBitmap.Decode(imageData); + byte[] imageData = ByteHelper.HexToBytes(graphicField.Data); + SKBitmap image = SKBitmap.Decode(imageData); - var x = graphicField.PositionX; - var y = graphicField.PositionY; + float x = graphicField.PositionX; + float y = graphicField.PositionY; - var useFieldTypeset = graphicField.FieldTypeset != null; + if (graphicField.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + bool useFieldTypeset = graphicField.FieldTypeset != null; if (useFieldTypeset) { y -= image.Height; + if (y < 0) + { + y = 0; + } } - this._skCanvas.DrawBitmap(image, x, y); + this.skCanvas.DrawBitmap(image, x, y); + return this.CalculateNextDefaultPosition(x, y, image.Width, image.Height, graphicField.FieldOrigin != null, Label.FieldOrientation.Normal, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/IElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/IElementDrawer.cs index cafc9e3a..16201acf 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/IElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/IElementDrawer.cs @@ -1,4 +1,6 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -30,14 +32,14 @@ void Prepare( /// /// bool IsReverseDraw(ZplElementBase element); - + /// /// Element is white /// /// /// bool IsWhiteDraw(ZplElementBase element); - + /// /// Element needs to be drawn in bitmap mode /// @@ -49,13 +51,30 @@ void Prepare( /// Draw the element /// /// - void Draw(ZplElementBase element); + /// + /// The current default field position for elements using default positioning + /// The updated default field position after drawing this element + SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition); + + /// + /// Draw the element with extra context information + /// + /// + /// + /// The current default field position for elements using default positioning + /// + /// The updated default field position after drawing this element + SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont); /// /// Draw the element with extra context information /// /// /// - void Draw(ZplElementBase element, DrawerOptions options); + /// The current default field position for elements using default positioning + /// + /// + /// The updated default field position after drawing this element + SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont, int printDensityDpmm); } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/ImageMoveElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/ImageMoveElementDrawer.cs index 73940668..dddb4ef0 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/ImageMoveElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/ImageMoveElementDrawer.cs @@ -1,4 +1,6 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -15,22 +17,43 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplImageMove imageMove) { - var imageData = this._printerStorage.GetFile(imageMove.StorageDevice, imageMove.ObjectName); + byte[] imageData = this.printerStorage.GetFile(imageMove.StorageDevice, imageMove.ObjectName); + SKBitmap image = SKBitmap.Decode(imageData); if (imageData.Length == 0) { - return; + return currentPosition; } - var x = imageMove.PositionX; - var y = imageMove.PositionY; + float x = imageMove.PositionX; + float y = imageMove.PositionY; - this._skCanvas.DrawBitmap(SKBitmap.Decode(imageData), x, y); + if (imageMove.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + bool useFieldTypeset = imageMove.FieldTypeset != null; + if (useFieldTypeset) + { + y -= image.Height; + if (y < 0) + { + y = 0; + } + } + + this.skCanvas.DrawBitmap(image, x, y); + + return this.CalculateNextDefaultPosition(x, y, image.Width, image.Height, imageMove.FieldOrigin != null, Label.FieldOrientation.Normal, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Interleaved2of5BarcodeDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Interleaved2of5BarcodeDrawer.cs index 2bf9f073..1192e6ef 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Interleaved2of5BarcodeDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Interleaved2of5BarcodeDrawer.cs @@ -1,6 +1,11 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; + using ZXing.OneD; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -17,30 +22,46 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplBarcodeInterleaved2of5 barcode) { float x = barcode.PositionX; float y = barcode.PositionY; - var writer = new ITFWriter(); - var result = writer.encode(barcode.Content); + if (barcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = barcode.Content; + if (barcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + ITFWriter writer = new(); + bool[] result = writer.encode(content); int narrow = barcode.ModuleWidth; int wide = (int)Math.Floor(barcode.WideBarToNarrowBarWidthRatio * narrow); - result = this.AdjustWidths(result, wide, narrow); - using var resizedImage = this.BoolArrayToSKBitmap(result, barcode.Height); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + result = AdjustWidths(result, wide, narrow); + using SKBitmap resizedImage = BoolArrayToSKBitmap(result, barcode.Height); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation); if (barcode.PrintInterpretationLine) { float labelFontSize = Math.Min(barcode.ModuleWidth * 10f, 100f); - var labelTypeFace = options.FontLoader("A"); - var labelFont = new SKFont(labelTypeFace, labelFontSize); - this.DrawInterpretationLine(barcode.Content, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); + SKTypeface labelTypeFace = options.FontLoader("A"); + SKFont labelFont = new(labelTypeFace, labelFontSize); + this.DrawInterpretationLine(content, labelFont, x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, barcode.PrintInterpretationLineAboveCode, options); } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, barcode.FieldOrigin != null, barcode.FieldOrientation, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/MaxiCodeElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/MaxiCodeElementDrawer.cs index b09b6755..92aa4fc2 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/MaxiCodeElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/MaxiCodeElementDrawer.cs @@ -1,13 +1,18 @@ -using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Label; +using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Helpers; -using CoelWu.Zint.Net; +using BinaryKits.Zpl.Viewer.Symologies; + +using SkiaSharp; + using System; -using System.IO; -using System.Drawing; -using System.Drawing.Drawing2D; +using System.Collections; namespace BinaryKits.Zpl.Viewer.ElementDrawers { + /// + /// Drawer for MaxiCode Barcode Elements. + /// public class MaxiCodeElementDrawer : BarcodeDrawerBase { /// @@ -17,145 +22,190 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont, int printDensityDpmm) { if (element is ZplMaxiCode maxiCode) { - var maxiBarcode = new ZintNetLib(); - maxiBarcode.MaxicodeMode = ConvertMaxiCodeMode(maxiCode.Mode); - var content = maxiCode.Content; - - try + float x = maxiCode.PositionX; + float y = maxiCode.PositionY; + + if (maxiCode.UseDefaultPosition) { - //replace hex items before mode 2 and mode 3 specific string manipulation - if (maxiCode.UseHexadecimalIndicator) - { - content = content.ReplaceHexEscapes(); - } - - if (maxiBarcode.MaxicodeMode == MaxicodeMode.Mode2) - { - //ZPL mode 2: - //^FD[aaa][bbb][ccccc][dddd]_5B)>_1E[ee]_1D[ff]1Z - //^FD002840100450000_5B)>_1E01_1D961Z - // = aaabbbcccccdddd - // aaa = three-digit class of service - // bbb = three-digit country code - // ccccc = five-digit zip code - // dddd = four-digit zip code extension (if none exists, four zeros (0000) must be entered) - // ee = 01 - // ff = year number - //ZintNetLib structure: - //^FD_5B)>_1E[ee]_1D[ff][ccccc][dddd]_1D[bbb]_1D[aaa]_1D1Z - //^FD_5B)>_1E01_1D96100450000_1D840_1D002_1D1Z - //Note: Country code 630 is not allowed in this library for mode 2 - - var replace = content.Substring(0, 24); - var aaa = content.Substring(0, 3); - var bbb = content.Substring(3, 3); - var ccccc = content.Substring(6, 5); - var dddd = content.Substring(11, 4); - var ee = content.Substring(19, 2); - var ff = content.Substring(22, 2); - var newString = $"\x5B)>\x1E{ee}\x1D{ff}{ccccc}{dddd}\x1D{bbb}\x1D{aaa}\x1D"; - content = content.Replace(replace, newString); - } - else if (maxiBarcode.MaxicodeMode == MaxicodeMode.Mode3) - { - //ZPL mode 3: - //^FD[aaa][bbb][cccccc]_5B)>_1E[ee]_1D[ff]1Z - //^FD066826RS19 _5B)>_1E01_1D961Z - // = aaabbbcccccc - // aaa = three-digit class of service - // bbb = three-digit country code - // ccccc = six-digit zip code (A through Z or 0 to 9) - // ee = 01 - // ff = year number - //ZintNetLib structure: - //^FD_5B)>_1E[ee]_1D[ff][cccccc]_1D[bbb]_1D[aaa]_1D1Z - //^FD_5B)>_1E01_1D96RS19 _1D826_1D066_1D1Z - - var replace = content.Substring(0, 21); - var aaa = content.Substring(0, 3); - var bbb = content.Substring(3, 3); - var cccccc = content.Substring(6, 6); - var ee = content.Substring(16, 2); - var ff = content.Substring(19, 2); - var newString = $"\x5B)>\x1E{ee}\x1D{ff}{cccccc}\x1D{bbb}\x1D{aaa}\x1D"; - content = content.Replace(replace, newString); - } - - maxiBarcode.CreateBarcode("Maxicode(ISO 16023)", content); + x = currentPosition.X; + y = currentPosition.Y; } - catch + + string content = maxiCode.Content; + if (maxiCode.HexadecimalIndicator is char hexIndicator) { - // Do nothing + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); } - //^BD2,1,1 - if (maxiBarcode.IsValid) + bool[] data = MaxiCodeSymbology.Encode(content, maxiCode.Mode); + + SKBitmap image = DrawMaxiCode(data, printDensityDpmm); + byte[] png = image.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + this.DrawBarcode(png, x, y, image.Width, image.Height, maxiCode.FieldOrigin != null, maxiCode.FieldOrientation); + return this.CalculateNextDefaultPosition(x, y, image.Width, image.Height, maxiCode.FieldOrigin != null, maxiCode.FieldOrientation, currentPosition); + } + + return currentPosition; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Match documentation.", Scope = "member")] + private static SKBitmap DrawMaxiCode(bool[] data, int dpmm) + { + // ISO/IEC 16023:2000 pp. 16, 38-40 + // fundamental dimensions + float L, H, W, V, X, Y; + + // gutters + float gX, gV; + + // dark hex pattern + SKPoint[] pattern; + float xoff, yoff; + + if (dpmm == 8) + { + W = 7; + V = 8; + X = W; + Y = 6; + + gX = 1; + gV = 1; + + xoff = 4f; + yoff = 2f; + pattern = [ + new SKPoint(0f, 3f), + new SKPoint(2f, 2f), + new SKPoint(1.5f, 0f), + new SKPoint(2f, -2f), + new SKPoint(0f, -3f), + new SKPoint(-2f, -2f), + new SKPoint(-1.5f, 0f) + ]; + + L = 29 * W; + H = 32 * Y; + } + else if (dpmm == 12) + { + W = 10; + V = 12; + X = W; + Y = 9; + + gX = 2; + gV = 2; + + xoff = 5f; + yoff = 3f; + pattern = [ + new SKPoint(0f, 4f), + new SKPoint(3f, 3f), + new SKPoint(1.5f, 0f), + new SKPoint(3f, -3f), + new SKPoint(0f, -4f), + new SKPoint(-3f, -3f), + new SKPoint(-1.5f, 0f) + ]; + + L = 29 * W; + H = 32 * Y; + } + else + { + L = 25.50f * dpmm; + + W = L / 29; + V = 1.1547f * W; // (2/Math.Sqrt(3)) * W + X = W; + Y = 0.866f * W; // (Math.Sqrt(3)/2) * W + + H = 32 * Y; + + gX = dpmm / 6f; + gV = 1.1547f * gX; + + xoff = W / 2; + yoff = (V - gV) / 4; + + // drawn hexagon dimensions + float hexW = (X - gX) / 2; // half width + float hexH = (V - gV) / 4; // quarter height + + pattern = [ + new SKPoint(0f, hexH * 2), + new SKPoint(hexW, hexH), + new SKPoint(hexW, -hexH), + new SKPoint(0f, -hexH * 2), + new SKPoint(-hexW, -hexH) + ]; + } + + // finder radii + float R1 = 0.51f * dpmm; + float R2 = 1.18f * dpmm; + float R3 = 1.86f * dpmm; + float R4 = 2.53f * dpmm; + float R5 = 3.20f * dpmm; + float R6 = 3.87f * dpmm; + + using SKBitmap image = new((int)Math.Ceiling(L + X - gX), (int)Math.Ceiling(H + V - gV)); + using SKCanvas skCanvas = new(image); + using SKPaint skPaint = new() + { + IsAntialias = false, + Color = SKColors.Black, + Style = SKPaintStyle.Fill, + }; + + SKPath path = new(); + IEnumerator dataEnum = data.GetEnumerator(); + for (int j = 0; j < 33; j++) + { + for (int i = 0; i < 30 - j % 2; i++) { - var bitmap = new Bitmap(1000, 1000); - var graphics = Graphics.FromImage(bitmap); - graphics.Clear(Color.White); - - maxiBarcode.Rotation = 0; - maxiBarcode.Multiplier = 2; - //Note: Position and Total are not supported in this MaxiCode library - maxiBarcode.DrawBarcode(graphics, new Point(-6, -6)); - - //Linux container fix, redraw the circles (variation of: CoelWu.Zint.Net.ZintNetLib.DrawBarcode) - graphics.SmoothingMode = SmoothingMode.AntiAlias; - float num3 = 13.64f * 7f; - float num4 = 13.43f * 7f; - float num5 = 0.85f * 7f; - float num6 = 2.2f * 7f; - float num7 = 3.54f * 7f; - Pen pen = new Pen(Color.Black, 0.67f * 7f); - graphics.DrawEllipse(pen, new RectangleF(num3 - num5 + 1, num4 - num5 + 1, num5 * 2.12f, num5 * 2.12f)); - graphics.DrawEllipse(pen, new RectangleF(num3 - num6 + 0.5f, num4 - num6 + 0.5f, num6 * 2.12f, num6 * 2.12f)); - graphics.DrawEllipse(pen, new RectangleF(num3 - num7, num4 - num7, num7 * 2.12f, num7 * 2.12f)); - - Size symbolSize; - var section = Rectangle.Empty; - symbolSize = maxiBarcode.SymbolSize(graphics); - section.Width = symbolSize.Width - 12; - section.Height = symbolSize.Height - 12; - - var newBitmap = new Bitmap(section.Width, section.Height); - var newGraphics = Graphics.FromImage(newBitmap); - newGraphics.DrawImage(bitmap, 0, 0, section, GraphicsUnit.Pixel); - - byte[] data = null; - using (MemoryStream ms = new MemoryStream()) + dataEnum.MoveNext(); + if ((bool)dataEnum.Current) { - newBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); - data = ms.ToArray(); - - this.DrawBarcode( - data, - maxiCode.PositionX, - maxiCode.PositionY, - section.Width, - section.Height, - true, - Label.FieldOrientation.Normal - ); + path.MoveTo(i * W + j % 2 * xoff, j * Y + yoff); + foreach (SKPoint point in pattern) + { + path.RLineTo(point); + } + + path.Close(); } } } - } - private MaxicodeMode ConvertMaxiCodeMode(int mode) - { - return mode switch { - 2 => MaxicodeMode.Mode2, - 3 => MaxicodeMode.Mode3, - 4 => MaxicodeMode.Mode4, - 5 => MaxicodeMode.Mode5, - 6 => MaxicodeMode.Mode6, - _ => MaxicodeMode.Mode2, - }; + float finderX = 14 * W + (X - gX) / 2; + float finderY = 16 * Y + (V - gV) / 2; + + path.AddCircle(finderX, finderY, R1, SKPathDirection.CounterClockwise); + path.AddCircle(finderX, finderY, R2, SKPathDirection.Clockwise); + path.Close(); + path.AddCircle(finderX, finderY, R3, SKPathDirection.CounterClockwise); + path.AddCircle(finderX, finderY, R4, SKPathDirection.Clockwise); + path.Close(); + path.AddCircle(finderX, finderY, R5, SKPathDirection.CounterClockwise); + path.AddCircle(finderX, finderY, R6, SKPathDirection.Clockwise); + path.Close(); + + skCanvas.DrawPath(path, skPaint); + + // labelary + //return image.Resize(new SKSizeI(200, 193), SKFilterQuality.High); // 8dpmm + //return image.Resize(new SKSizeI(300, 289), SKFilterQuality.High); // 12dpmm + //return image.Resize(new SKSizeI(600, 579), SKFilterQuality.High); // 24dpmm + + // ISO + return image.Copy(); } + } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs index 1ecca2ec..5e0de7fb 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs @@ -1,8 +1,12 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; using System.Collections.Generic; + using ZXing; using ZXing.Common; using ZXing.PDF417; @@ -22,19 +26,35 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplPDF417 pdf417) { if (pdf417.Height == 0) - throw new System.Exception("PDF417 Height is set to zero."); + { + throw new Exception("PDF417 Height is set to zero."); + } - if (string.IsNullOrWhiteSpace(pdf417.Content)) - throw new System.Exception("PDF147 Content is empty."); + string content = pdf417.Content; + if (pdf417.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + + if (string.IsNullOrWhiteSpace(content)) + { + throw new Exception("PDF147 Content is empty."); + } float x = pdf417.PositionX; float y = pdf417.PositionY; + if (pdf417.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + int mincols, maxcols, minrows, maxrows; if (pdf417.Rows != null) { @@ -66,8 +86,9 @@ public override void Draw(ZplElementBase element) minrows /= 2; } } - var writer = new PDF417Writer(); - var hints = new Dictionary { + + PDF417Writer writer = new(); + Dictionary hints = new() { // { EncodeHintType.CHARACTER_SET, "ISO-8859-1" }, { EncodeHintType.PDF417_COMPACT, pdf417.Compact }, //{ EncodeHintType.PDF417_AUTO_ECI, true }, @@ -79,29 +100,35 @@ public override void Draw(ZplElementBase element) { EncodeHintType.ERROR_CORRECTION, ConvertErrorCorrection(pdf417.SecurityLevel) }, { EncodeHintType.PDF417_DIMENSIONS, new Dimensions(mincols, maxcols, minrows, maxrows) }, }; - - var default_bitmatrix = writer.encode(pdf417.Content, BarcodeFormat.PDF_417, 0, 0, hints); - + + BitMatrix default_bitmatrix = writer.encode(content, BarcodeFormat.PDF_417, 0, 0, hints); + //PDF417_ASPECT_RATIO set to 3, we need to multiply that with pdf417.ModuleWidth (defined by ^BY) - var bar_height = pdf417.ModuleWidth * 3; - var upscaled = proportional_upscale(default_bitmatrix, pdf417.ModuleWidth); - var result = vertical_scale(upscaled, pdf417.Height, bar_height); - - using var resizedImage = this.BitMatrixToSKBitmap(result, 1); + int bar_height = pdf417.ModuleWidth * 3; + BitMatrix upscaled = ProportionalUpscale(default_bitmatrix, pdf417.ModuleWidth); + BitMatrix result = VerticalScale(upscaled, pdf417.Height, bar_height); + + using SKBitmap resizedImage = BitMatrixToSKBitmap(result, 1); { - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y, resizedImage.Width, resizedImage.Height, pdf417.FieldOrigin != null, pdf417.FieldOrientation); } + + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height, pdf417.FieldOrigin != null, pdf417.FieldOrientation, currentPosition); } + + return currentPosition; } // bitmatrix scaling instead of bitmap - private BitMatrix proportional_upscale(BitMatrix old, int scale) { + private static BitMatrix ProportionalUpscale(BitMatrix old, int scale) + { if (scale == 0 || scale == 1) { return old; } - BitMatrix upscaled = new BitMatrix(old.Width * scale, old.Height * scale); + + BitMatrix upscaled = new(old.Width * scale, old.Height * scale); for (int i = 0; i < old.Height; i++) { BitArray old_row = old.getRow(i, null); @@ -112,9 +139,11 @@ private BitMatrix proportional_upscale(BitMatrix old, int scale) { { continue; } + upscaled.setRegion(j * scale, i * scale, scale, scale); } } + return upscaled; } @@ -123,7 +152,8 @@ private BitMatrix proportional_upscale(BitMatrix old, int scale) { // - we can only set the height in zpl in points, not the width // - each bar is ^BY "points" thick // - because we have PDF417_ASPECT_RATIO set to 3, the height of a single bar is now 3 * ^BY - private BitMatrix vertical_scale(BitMatrix old_matrix, int new_bar_height, int old_bar_height) { + private static BitMatrix VerticalScale(BitMatrix old_matrix, int new_bar_height, int old_bar_height) + { int width = old_matrix.Width; int rows = old_matrix.Height / old_bar_height; // logical rows; @@ -132,7 +162,7 @@ private BitMatrix vertical_scale(BitMatrix old_matrix, int new_bar_height, int o return old_matrix; } - BitMatrix scaled = new BitMatrix(old_matrix.Width, rows * new_bar_height); + BitMatrix scaled = new(old_matrix.Width, rows * new_bar_height); for (int i = 0; i < rows; i++) { @@ -144,13 +174,15 @@ private BitMatrix vertical_scale(BitMatrix old_matrix, int new_bar_height, int o { continue; } + scaled.setRegion(j, i * new_bar_height, 1, new_bar_height); } } + return scaled; } - private PDF417ErrorCorrectionLevel ConvertErrorCorrection(int correction) + private static PDF417ErrorCorrectionLevel ConvertErrorCorrection(int correction) { return correction switch { diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs index 701555f6..2ba67de7 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs @@ -1,9 +1,13 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; -using System.Collections.Generic; + using System.Text.RegularExpressions; + using ZXing; +using ZXing.Common; using ZXing.QrCode; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -13,7 +17,7 @@ namespace BinaryKits.Zpl.Viewer.ElementDrawers /// public class QrCodeElementDrawer : BarcodeDrawerBase { - private static readonly Regex gs1Regex = new Regex(@"^>;>8(.+)$", RegexOptions.Compiled); + private static readonly Regex gs1Regex = new(@"^>;>8(.+)$", RegexOptions.Compiled); /// public override bool CanDraw(ZplElementBase element) @@ -22,17 +26,27 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplQrCode qrcode) { float x = qrcode.PositionX; float y = qrcode.PositionY; - + + if (qrcode.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + string content = qrcode.Content; + if (qrcode.HexadecimalIndicator is char hexIndicator) + { + content = content.ReplaceHexEscapes(hexIndicator, internationalFont); + } + // support hand-rolled GS1 bool gs1Mode = false; - var content = qrcode.Content; - Match gs1Match = gs1Regex.Match(content); if (gs1Match.Success) { @@ -42,25 +56,28 @@ public override void Draw(ZplElementBase element) int verticalQuietZone = 10; - var writer = new QRCodeWriter(); - // TODO: use QrCodeEncodingOptions in next version of ZXing.NET - var hints = new Dictionary { - { EncodeHintType.ERROR_CORRECTION, CovertErrorCorrection(qrcode.ErrorCorrectionLevel) }, - { EncodeHintType.QR_MASK_PATTERN, qrcode.MaskValue }, - { EncodeHintType.CHARACTER_SET, "UTF-8" }, - { EncodeHintType.MARGIN, 0 }, - { EncodeHintType.GS1_FORMAT, gs1Mode } + QRCodeWriter writer = new(); + QrCodeEncodingOptions encodingOptions = new() + { + ErrorCorrection = ConvertErrorCorrection(qrcode.ErrorCorrectionLevel), + QrMaskPattern = qrcode.MaskValue, + CharacterSet = "UTF-8", + Margin = 0, + GS1Format = gs1Mode }; - var result = writer.encode(content, BarcodeFormat.QR_CODE, 0, 0, hints); + BitMatrix result = writer.encode(content, BarcodeFormat.QR_CODE, 0, 0, encodingOptions.Hints); - using var resizedImage = this.BitMatrixToSKBitmap(result, qrcode.MagnificationFactor); + using SKBitmap resizedImage = BitMatrixToSKBitmap(result, qrcode.MagnificationFactor); - var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); + byte[] png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); this.DrawBarcode(png, x, y + verticalQuietZone, resizedImage.Width, resizedImage.Height + 2 * verticalQuietZone, qrcode.FieldOrigin != null, qrcode.FieldOrientation); + return this.CalculateNextDefaultPosition(x, y, resizedImage.Width, resizedImage.Height + 2 * verticalQuietZone, qrcode.FieldOrigin != null, qrcode.FieldOrientation, currentPosition); } + + return currentPosition; } - private ZXing.QrCode.Internal.ErrorCorrectionLevel CovertErrorCorrection(ErrorCorrectionLevel errorCorrectionLevel) + private static ZXing.QrCode.Internal.ErrorCorrectionLevel ConvertErrorCorrection(ErrorCorrectionLevel errorCorrectionLevel) { return errorCorrectionLevel switch { diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/RecallGraphicElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/RecallGraphicElementDrawer.cs index 8e025e2e..a660c1bc 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/RecallGraphicElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/RecallGraphicElementDrawer.cs @@ -1,4 +1,6 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; + using SkiaSharp; namespace BinaryKits.Zpl.Viewer.ElementDrawers @@ -15,27 +17,44 @@ public override bool CanDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplRecallGraphic recallGraphic) { - var imageData = this._printerStorage.GetFile(recallGraphic.StorageDevice, recallGraphic.ImageName); + byte[] imageData = this.printerStorage.GetFile(recallGraphic.StorageDevice, recallGraphic.ImageName); if (imageData.Length == 0) { - return; + return currentPosition; } - var x = recallGraphic.PositionX; - var y = recallGraphic.PositionY; - var bitmap = SKBitmap.Decode(imageData); + float x = recallGraphic.PositionX; + float y = recallGraphic.PositionY; + + if (recallGraphic.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } + + SKBitmap bitmap = SKBitmap.Decode(imageData); if (recallGraphic.FieldTypeset != null) { y -= bitmap.Height; + if (y < 0) + { + y = 0; + } } - this._skCanvas.DrawBitmap(bitmap, x, y); + this.skCanvas.DrawBitmap(bitmap, x, y); + + float width = bitmap.Width; + float height = bitmap.Height; + return this.CalculateNextDefaultPosition(x, y, width, height, recallGraphic.FieldOrigin != null, FieldOrientation.Normal, currentPosition); } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/TextFieldElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/TextFieldElementDrawer.cs index 3659e855..1419a869 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/TextFieldElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/TextFieldElementDrawer.cs @@ -1,5 +1,7 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; using SkiaSharp.HarfBuzz; @@ -13,6 +15,7 @@ public override bool CanDraw(ZplElementBase element) return element.GetType() == typeof(ZplTextField); } + /// public override bool IsReverseDraw(ZplElementBase element) { if (element is ZplTextField textField) @@ -24,34 +27,41 @@ public override bool IsReverseDraw(ZplElementBase element) } /// - public override void Draw(ZplElementBase element, DrawerOptions options) + public override SKPoint Draw(ZplElementBase element, DrawerOptions options, SKPoint currentPosition, InternationalFont internationalFont) { if (element is ZplTextField textField) { float x = textField.PositionX; float y = textField.PositionY; + FieldJustification fieldJustification = Label.FieldJustification.None; + + if (textField.UseDefaultPosition) + { + x = currentPosition.X; + y = currentPosition.Y; + } - var font = textField.Font; + ZplFont font = textField.Font; float fontSize = font.FontHeight > 0 ? font.FontHeight : font.FontWidth; - var scaleX = 1.00f; + float scaleX = 1.00f; if (font.FontWidth != 0 && font.FontWidth != fontSize) { scaleX *= (float)font.FontWidth / fontSize; } - var typeface = options.FontLoader(font.FontName); + SKTypeface typeface = options.FontLoader(font.FontName); - var skFont = new SKFont(typeface, fontSize, scaleX); - using var skPaint = new SKPaint(skFont) + SKFont skFont = new(typeface, fontSize, scaleX); + using SKPaint skPaint = new() { IsAntialias = options.Antialias }; string displayText = textField.Text; - if (textField.UseHexadecimalIndicator) + if (textField.HexadecimalIndicator is char hexIndicator) { - displayText = displayText.ReplaceHexEscapes(); + displayText = displayText.ReplaceHexEscapes(hexIndicator, internationalFont); } if (options.ReplaceDashWithEnDash) @@ -59,12 +69,15 @@ public override void Draw(ZplElementBase element, DrawerOptions options) displayText = displayText.Replace("-", " \u2013 "); } - var textBounds = new SKRect(); - var textBoundBaseline = new SKRect(); - skPaint.MeasureText("X", ref textBoundBaseline); - skPaint.MeasureText(displayText, ref textBounds); + if (options.ReplaceUnderscoreWithEnSpace) + { + displayText = displayText.Replace('_', '\u2002'); + } + + skFont.MeasureText("X", out SKRect textBoundBaseline); + float totalWidth = skFont.MeasureText(displayText, out SKRect textBounds); - using (new SKAutoCanvasRestore(this._skCanvas)) + using (new SKAutoCanvasRestore(this.skCanvas)) { SKMatrix matrix = SKMatrix.Empty; @@ -72,40 +85,44 @@ public override void Draw(ZplElementBase element, DrawerOptions options) { switch (textField.Font.FieldOrientation) { - case Label.FieldOrientation.Rotated90: + case FieldOrientation.Rotated90: matrix = SKMatrix.CreateRotationDegrees(90, x + fontSize / 2, y + fontSize / 2); break; - case Label.FieldOrientation.Rotated180: + case FieldOrientation.Rotated180: matrix = SKMatrix.CreateRotationDegrees(180, x + textBounds.Width / 2, y + fontSize / 2); break; - case Label.FieldOrientation.Rotated270: + case FieldOrientation.Rotated270: matrix = SKMatrix.CreateRotationDegrees(270, x + textBounds.Width / 2, y + textBounds.Width / 2); break; - case Label.FieldOrientation.Normal: + case FieldOrientation.Normal: break; } + + fieldJustification = textField.FieldOrigin.FieldJustification; } else { switch (textField.Font.FieldOrientation) { - case Label.FieldOrientation.Rotated90: + case FieldOrientation.Rotated90: matrix = SKMatrix.CreateRotationDegrees(90, x, y); break; - case Label.FieldOrientation.Rotated180: + case FieldOrientation.Rotated180: matrix = SKMatrix.CreateRotationDegrees(180, x, y); break; - case Label.FieldOrientation.Rotated270: + case FieldOrientation.Rotated270: matrix = SKMatrix.CreateRotationDegrees(270, x, y); break; - case Label.FieldOrientation.Normal: + case FieldOrientation.Normal: break; } + + fieldJustification = textField.FieldTypeset.FieldJustification; } if (matrix != SKMatrix.Empty) { - this._skCanvas.SetMatrix(matrix); + this.skCanvas.Concat(matrix); } if (textField.FieldTypeset == null) @@ -118,9 +135,34 @@ public override void Draw(ZplElementBase element, DrawerOptions options) skPaint.BlendMode = SKBlendMode.Xor; } - this._skCanvas.DrawShapedText(displayText, x, y, skPaint); + SKTextAlign textAlign = SKTextAlign.Left; + if (fieldJustification == FieldJustification.Left) + { + textAlign = SKTextAlign.Left; + } + else if (fieldJustification == FieldJustification.Right) + { + textAlign = SKTextAlign.Right; + } + else if (fieldJustification == FieldJustification.Auto) + { + HarfBuzzSharp.Buffer buffer = new(); + buffer.AddUtf16(displayText); + buffer.GuessSegmentProperties(); + if (buffer.Direction == HarfBuzzSharp.Direction.RightToLeft) + { + textAlign = SKTextAlign.Right; + } + } + + this.skCanvas.DrawShapedText(displayText, x, y, textAlign, skFont, skPaint); + + // Update the next default field position after rendering + return this.CalculateNextDefaultPosition(x, y, totalWidth, textBounds.Height, false, textField.Font.FieldOrientation, currentPosition); } } + + return currentPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/FormatMerger.cs b/src/BinaryKits.Zpl.Viewer/FormatMerger.cs index d601217f..587367ec 100644 --- a/src/BinaryKits.Zpl.Viewer/FormatMerger.cs +++ b/src/BinaryKits.Zpl.Viewer/FormatMerger.cs @@ -1,9 +1,10 @@ -using System; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using BinaryKits.Zpl.Label.Elements; -using BinaryKits.Zpl.Viewer.Models; namespace BinaryKits.Zpl.Viewer { @@ -15,14 +16,14 @@ public class FormatMerger : IFormatMerger /// public List MergeFormats(List rawLabelInfos) { - var mergedLabelInfos = new List(); + List mergedLabelInfos = []; // Format label infos indexed by download format name - var templateFormats = new Dictionary(); + Dictionary templateFormats = []; - foreach (var rawLabelInfo in rawLabelInfos) + foreach (LabelInfo rawLabelInfo in rawLabelInfos) { - var elements = GetMergedElements(rawLabelInfo, templateFormats); - var labelInfo = new LabelInfo { ZplElements = elements.ToArray() }; + List elements = GetMergedElements(rawLabelInfo, templateFormats); + LabelInfo labelInfo = new() { ZplElements = elements.ToArray() }; if (rawLabelInfo.DownloadFormatName != null) { @@ -41,7 +42,7 @@ private static List GetMergedElements( LabelInfo rawLabelInfo, Dictionary templateFormats) { - var elements = new List(); + List elements = []; foreach (ZplElementBase zplElement in rawLabelInfo.ZplElements) { @@ -52,7 +53,7 @@ private static List GetMergedElements( } else if (zplElement is ZplRecallFieldNumber recallFieldNumber) { - for(int i = 0; i < elements.Count; i++) + for (int i = 0; i < elements.Count; i++) { if (elements[i] is ZplFieldNumber fieldNumber && fieldNumber.Number == recallFieldNumber.Number) { @@ -75,12 +76,12 @@ private static LabelInfo GetFormatLabelInfo( Dictionary templateFormats) { string formatName = Path.GetFileNameWithoutExtension(recallFormat.FormatName); - if (!templateFormats.ContainsKey(formatName)) + if (!templateFormats.TryGetValue(formatName, out LabelInfo value)) { throw new InvalidOperationException($"Could not find format {recallFormat.FormatName}"); } - return templateFormats[formatName]; + return value; } /// @@ -92,13 +93,13 @@ private static IEnumerable GetMergedElements( LabelInfo valuesLabelInfo, LabelInfo formatLabelInfo) { - foreach (var formatElement in formatLabelInfo.ZplElements) + foreach (ZplElementBase formatElement in formatLabelInfo.ZplElements) { if (formatElement is ZplFieldNumber fieldNumber) { if (fieldNumber.FormatElement != null) { - var recallFieldNumber = (ZplRecallFieldNumber)valuesLabelInfo.ZplElements.FirstOrDefault(e => + ZplRecallFieldNumber recallFieldNumber = (ZplRecallFieldNumber)valuesLabelInfo.ZplElements.FirstOrDefault(e => (e as ZplRecallFieldNumber)?.Number == fieldNumber.Number); if (recallFieldNumber != null) { diff --git a/src/BinaryKits.Zpl.Viewer/Helpers/ImageHelper.cs b/src/BinaryKits.Zpl.Viewer/Helpers/ImageHelper.cs index f5df3054..776ad5f2 100644 --- a/src/BinaryKits.Zpl.Viewer/Helpers/ImageHelper.cs +++ b/src/BinaryKits.Zpl.Viewer/Helpers/ImageHelper.cs @@ -1,14 +1,14 @@ using BinaryKits.Zpl.Label.Helpers; -using System; + using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.Helpers { internal static class ImageHelper { - private static readonly Regex hexDataRegex = new Regex("^[0-9A-Fa-f]+$", RegexOptions.Compiled); - private static readonly Regex z64DataRegex = new Regex(":(Z64):(\\S+):([0-9a-fA-F]+)", RegexOptions.Compiled); - private static readonly Regex b64DataRegex = new Regex(":(B64):(\\S+):([0-9a-fA-F]+)", RegexOptions.Compiled); + private static readonly Regex hexDataRegex = new("^[0-9A-Fa-f]+$", RegexOptions.Compiled); + private static readonly Regex z64DataRegex = new(":(Z64):(\\S+):([0-9a-fA-F]+)", RegexOptions.Compiled); + private static readonly Regex b64DataRegex = new(":(B64):(\\S+):([0-9a-fA-F]+)", RegexOptions.Compiled); public static byte[] GetImageBytes(string dataHex, int bytesPerRow) { @@ -16,14 +16,17 @@ public static byte[] GetImageBytes(string dataHex, int bytesPerRow) { return ZebraZ64CompressionHelper.Uncompress(dataHex); } + if (b64DataRegex.IsMatch(dataHex)) { return ZebraB64CompressionHelper.Uncompress(dataHex); } + if (hexDataRegex.IsMatch(dataHex)) { return dataHex.ToBytesFromHex(); } + return ZebraACSCompressionHelper.Uncompress(dataHex, bytesPerRow).ToBytesFromHex(); } } diff --git a/src/BinaryKits.Zpl.Viewer/Helpers/StringHelper.cs b/src/BinaryKits.Zpl.Viewer/Helpers/StringHelper.cs index 5bd3fe5c..08107280 100644 --- a/src/BinaryKits.Zpl.Viewer/Helpers/StringHelper.cs +++ b/src/BinaryKits.Zpl.Viewer/Helpers/StringHelper.cs @@ -1,25 +1,67 @@ -using System; +using BinaryKits.Zpl.Label; + +using System.Collections.Generic; using System.Globalization; +using System.Text; using System.Text.RegularExpressions; namespace BinaryKits.Zpl.Viewer.Helpers { public static class StringHelper { - /// - /// The hexadecimal indicator from the ^FH - /// - public static char ReplaceChar { get; set; } = '_'; + private static readonly Regex hexDigits = new(@"^[0-9A-Fa-f]{2}$", RegexOptions.Compiled); + + static StringHelper() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + } /// /// Replaces hex escapes within a text. /// /// Topic variable + /// Character which indicates a hex escape + /// Byte encoding for escaped hex /// Text with hex escapes replaced with their char equivalents. - public static string ReplaceHexEscapes(this string text) + public static string ReplaceHexEscapes(this string text, char hexIndicator, InternationalFont internationalFont) + { + Encoding charset = GetCharset(internationalFont); + List bytes = []; + for (int i = 0; i < text.Length; i++) + { + char c = text[i]; + if (c == hexIndicator && i + 2 < text.Length) + { + string digits = text.Substring(i + 1, 2); + if (hexDigits.IsMatch(digits)) + { + bytes.Add(byte.Parse(digits, NumberStyles.HexNumber)); + i += 2; + continue; + } + } + + bytes.AddRange(charset.GetBytes(c.ToString())); + } + + return charset.GetString(bytes.ToArray()); + } + + private static Encoding GetCharset(InternationalFont internationalFont) { - Regex hexEscapeRegex = new Regex(Regex.Escape(ReplaceChar.ToString()) + @"([0-9A-Fa-f]{2})"); - return hexEscapeRegex.Replace(text, match => Convert.ToChar(int.Parse(match.Groups[1].Value, NumberStyles.HexNumber)).ToString()); + return internationalFont switch + { + InternationalFont.UTF8 => Encoding.UTF8, + InternationalFont.UTF16_BE => Encoding.BigEndianUnicode, + InternationalFont.UTF16_LE => Encoding.Unicode, + InternationalFont.ZCP1250 => Encoding.GetEncoding(1250), + InternationalFont.ZCP1251 => Encoding.GetEncoding(1251), + InternationalFont.ZCP1252 => Encoding.GetEncoding(1252), + InternationalFont.ZCP1253 => Encoding.GetEncoding(1253), + InternationalFont.ZCP1254 => Encoding.GetEncoding(1254), + InternationalFont.ZCP1255 => Encoding.GetEncoding(1255), + _ => Encoding.GetEncoding(850), + }; } } } diff --git a/src/BinaryKits.Zpl.Viewer/Helpers/UnitsHelper.cs b/src/BinaryKits.Zpl.Viewer/Helpers/UnitsHelper.cs new file mode 100644 index 00000000..8ecc9246 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Helpers/UnitsHelper.cs @@ -0,0 +1,10 @@ +namespace BinaryKits.Zpl.Viewer.Helpers +{ + internal static class UnitsHelper + { + internal static double ConvertMillimetersToInches(double labelWidth) + { + return labelWidth / 25.4; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/IFormatMerger.cs b/src/BinaryKits.Zpl.Viewer/IFormatMerger.cs index 94ddb94e..beb7500f 100644 --- a/src/BinaryKits.Zpl.Viewer/IFormatMerger.cs +++ b/src/BinaryKits.Zpl.Viewer/IFormatMerger.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; -using BinaryKits.Zpl.Viewer.Models; +using BinaryKits.Zpl.Viewer.Models; + +using System.Collections.Generic; namespace BinaryKits.Zpl.Viewer { @@ -16,6 +17,6 @@ public interface IFormatMerger /// /// Raw label infos as read by ZplAnalyzer /// Merged label info list - public List MergeFormats(List rawLabelInfos); + List MergeFormats(List rawLabelInfos); } -} \ No newline at end of file +} diff --git a/src/BinaryKits.Zpl.Viewer/IZplAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/IZplAnalyzer.cs index 81a7fc32..1f590043 100644 --- a/src/BinaryKits.Zpl.Viewer/IZplAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/IZplAnalyzer.cs @@ -1,9 +1,9 @@ using BinaryKits.Zpl.Viewer.Models; -namespace Application.UseCase.ZplToPdf +namespace BinaryKits.Zpl.Viewer { public interface IZplAnalyzer { - public AnalyzeInfo Analyze(string zplData); + AnalyzeInfo Analyze(string zplData); } } diff --git a/src/BinaryKits.Zpl.Viewer/Models/AnsiCodabarFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/AnsiCodabarFieldData.cs new file mode 100644 index 00000000..36e0a34b --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/AnsiCodabarFieldData.cs @@ -0,0 +1,15 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + public class AnsiCodabarFieldData : FieldDataBase + { + public FieldOrientation FieldOrientation { get; set; } + public int Height { get; set; } + public bool PrintInterpretationLine { get; set; } + public bool PrintInterpretationLineAboveCode { get; set; } + public bool CheckDigit { get; set; } + public char StartCharacter { get; set; } + public char StopCharacter { get; set; } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Models/AztecBarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/AztecBarcodeFieldData.cs new file mode 100644 index 00000000..7d89e44e --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/AztecBarcodeFieldData.cs @@ -0,0 +1,16 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + public class AztecBarcodeFieldData : FieldDataBase + { + public FieldOrientation FieldOrientation { get; set; } + public int MagnificationFactor { get; set; } + public bool ExtendedChannel { get; set; } + public int ErrorControl { get; set; } + public bool MenuSymbol { get; set; } + public int SymbolCount { get; set; } + public string IdField { get; set; } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Models/CodeEAN13BarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/CodeEAN13BarcodeFieldData.cs index b5ffd473..29078db9 100644 --- a/src/BinaryKits.Zpl.Viewer/Models/CodeEAN13BarcodeFieldData.cs +++ b/src/BinaryKits.Zpl.Viewer/Models/CodeEAN13BarcodeFieldData.cs @@ -8,6 +8,6 @@ public class CodeEAN13BarcodeFieldData : FieldDataBase public int Height { get; set; } public bool PrintInterpretationLine { get; set; } public bool PrintInterpretationLineAboveCode { get; set; } - + } } diff --git a/src/BinaryKits.Zpl.Viewer/Models/DataMatrixFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/DataMatrixFieldData.cs index 924b1c93..115ec9fd 100644 --- a/src/BinaryKits.Zpl.Viewer/Models/DataMatrixFieldData.cs +++ b/src/BinaryKits.Zpl.Viewer/Models/DataMatrixFieldData.cs @@ -6,5 +6,6 @@ public class DataMatrixFieldData : FieldDataBase { public FieldOrientation FieldOrientation { get; set; } public int Height { get; set; } + public QualityLevel QualityLevel { get; set; } } } diff --git a/src/BinaryKits.Zpl.Viewer/Models/LabelPosition.cs b/src/BinaryKits.Zpl.Viewer/Models/LabelPosition.cs index 23455f35..72f6443e 100644 --- a/src/BinaryKits.Zpl.Viewer/Models/LabelPosition.cs +++ b/src/BinaryKits.Zpl.Viewer/Models/LabelPosition.cs @@ -5,12 +5,14 @@ public class LabelPosition public int X { get; private set; } public int Y { get; private set; } public bool CalculateFromBottom { get; private set; } + public bool UseDefaultPosition { get; private set; } - public LabelPosition(int x, int y, bool calculateFromBottom) + public LabelPosition(int x, int y, bool calculateFromBottom, bool useDefaultPosition) { this.X = x; this.Y = y; this.CalculateFromBottom = calculateFromBottom; + this.UseDefaultPosition = useDefaultPosition; } } } diff --git a/src/BinaryKits.Zpl.Viewer/Models/MaxiCodeBarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/MaxiCodeBarcodeFieldData.cs index 2675180d..64d8135d 100644 --- a/src/BinaryKits.Zpl.Viewer/Models/MaxiCodeBarcodeFieldData.cs +++ b/src/BinaryKits.Zpl.Viewer/Models/MaxiCodeBarcodeFieldData.cs @@ -1,12 +1,9 @@ -using BinaryKits.Zpl.Label; - -namespace BinaryKits.Zpl.Viewer.Models +namespace BinaryKits.Zpl.Viewer.Models { public class MaxiCodeBarcodeFieldData : FieldDataBase { public int Mode { get; set; } public int Position { get; set; } public int Total { get; set; } - public bool UseHexadecimalIndicator { get; set; } } } diff --git a/src/BinaryKits.Zpl.Viewer/Models/UpcABarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/UpcABarcodeFieldData.cs new file mode 100644 index 00000000..1df1198c --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/UpcABarcodeFieldData.cs @@ -0,0 +1,13 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + internal class UpcABarcodeFieldData : FieldDataBase + { + public FieldOrientation FieldOrientation { get; set; } + public int Height { get; set; } + public bool PrintInterpretationLine { get; set; } + public bool PrintInterpretationLineAboveCode { get; set; } + public bool PrintCheckDigit { get; set; } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Models/UpcEBarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/UpcEBarcodeFieldData.cs new file mode 100644 index 00000000..62ae6569 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/UpcEBarcodeFieldData.cs @@ -0,0 +1,13 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + internal class UpcEBarcodeFieldData : FieldDataBase + { + public FieldOrientation FieldOrientation { get; set; } + public int Height { get; set; } + public bool PrintInterpretationLine { get; set; } + public bool PrintInterpretationLineAboveCode { get; set; } + public bool PrintCheckDigit { get; set; } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Models/UpcExtensionBarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/UpcExtensionBarcodeFieldData.cs new file mode 100644 index 00000000..9cf4e861 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/UpcExtensionBarcodeFieldData.cs @@ -0,0 +1,12 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + internal class UpcExtensionBarcodeFieldData : FieldDataBase + { + public FieldOrientation FieldOrientation { get; set; } + public int Height { get; set; } + public bool PrintInterpretationLine { get; set; } + public bool PrintInterpretationLineAboveCode { get; set; } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/PrinterStorage.cs b/src/BinaryKits.Zpl.Viewer/PrinterStorage.cs index 711bbe11..8b8ca817 100644 --- a/src/BinaryKits.Zpl.Viewer/PrinterStorage.cs +++ b/src/BinaryKits.Zpl.Viewer/PrinterStorage.cs @@ -1,25 +1,24 @@ -using System; using System.Collections.Concurrent; namespace BinaryKits.Zpl.Viewer { public class PrinterStorage : IPrinterStorage { - private readonly ConcurrentDictionary> _cache; + private readonly ConcurrentDictionary> cache; public PrinterStorage() { - this._cache = new ConcurrentDictionary>(); + this.cache = new ConcurrentDictionary>(); } public void AddFile(char storageDevice, string fileName, byte[] data) { - if (!this._cache.ContainsKey(storageDevice)) + if (!this.cache.ContainsKey(storageDevice)) { - this._cache.TryAdd(storageDevice, new ConcurrentDictionary()); + this.cache.TryAdd(storageDevice, new ConcurrentDictionary()); } - if (this._cache.TryGetValue(storageDevice, out var files)) + if (this.cache.TryGetValue(storageDevice, out ConcurrentDictionary files)) { files.TryAdd(fileName, data); } @@ -27,18 +26,18 @@ public void AddFile(char storageDevice, string fileName, byte[] data) public byte[] GetFile(char storageDevice, string fileName) { - if (!this._cache.ContainsKey(storageDevice)) + if (!this.cache.ContainsKey(storageDevice)) { - return Array.Empty(); + return []; } - if (this._cache.TryGetValue(storageDevice, out var files)) + if (this.cache.TryGetValue(storageDevice, out ConcurrentDictionary files)) { - files.TryGetValue(fileName, out var data); - return data ?? Array.Empty(); + files.TryGetValue(fileName, out byte[] data); + return data ?? []; } - return Array.Empty(); + return []; } } } diff --git a/src/BinaryKits.Zpl.Viewer/README.md b/src/BinaryKits.Zpl.Viewer/README.md index 9d72a1be..d531542d 100644 --- a/src/BinaryKits.Zpl.Viewer/README.md +++ b/src/BinaryKits.Zpl.Viewer/README.md @@ -1,3 +1,89 @@ +# BinaryKits.Zpl.Viewer + +## Supported Barcode Formats + +### 1D Barcodes +- [x] Code 39 (^B3) +- [x] Code 93 (^BA) +- [x] Code 128 (^BC) +- [x] EAN-13 (^BE) +- [x] UPC-A (^BU) +- [x] UPC-E (^B9) +- [x] UPC Extension (^BS) +- [x] Interleaved 2 of 5 (^B2) +- [x] ANSI Codabar (^BK) + +### 2D Barcodes +- [x] QR Code (^BQ) +- [x] Data Matrix (^BX) +- [x] PDF417 (^B7) +- [x] Aztec (^B0) +- [x] MaxiCode (^BD) + +## Unsupported Barcode Formats + +### 1D Barcodes +- [ ] MSI (^BM): Supported by ZXing.NET +- [ ] Databar/RSS-14 (^BR): Not supported by ZXing.NET +- [ ] Code 11 (^B1): Not supported by ZXing.NET, [simple to implement](https://web.archive.org/web/20070202060711/http://www.barcodeisland.com/code11.phtml) +- [ ] POSTNET (^BB): Not supported by ZXing.NET +- [ ] PLANET (^B8): Not supported by ZXing.NET +- [ ] Composite (^BC): Not supported by ZXing.NET, simple to implement + - **Note:** Shares command with Code 128 - requires special handling + +### 2D Barcodes +- [ ] Micro PDF417 (^B7): Not supported by ZXing.NET + - ASCII data only + - Appears to be a subset of PDF417 + - **Note:** Shares command with PDF417 - differentiated by mode parameter +- [ ] Micro QR Code (^BQ): Not supported by ZXing.NET + - Appears to be a subset of QR Code + - **Note:** Shares command with QR Code - differentiated by model parameter + +## Supported Label Elements + +### Text Elements +- [x] Text Field (^FD with ^A or ^CF) +- [x] Field Block (^FB) - Multi-line text with justification +- [x] Field Typeset (^FT) - Typeset field positioning +- [x] Scalable/Bitmapped Font (^A, ^CF) +- [x] Change International Font (^CI) +- [x] Hexadecimal Indicator (^FH) +- [x] Field Reverse Print (^FR) +- [x] Field Number (^FN) - Variable field for templates +- [x] Recall Field Number - Variable field data + +### Graphic Elements +- [x] Graphic Box (^GB) - Rectangle with optional fill +- [x] Graphic Circle (^GC) +- [x] Graphic Field (^GF) - Raster graphics +- [x] Image Move (^IM) - Recall stored image +- [x] Recall Graphic (^XG) - Recall stored graphic with scaling + +### Positioning & Layout +- [x] Field Origin (^FO) - Set field position +- [x] Field Separator (^FS) +- [x] Field Orientation (^FW) - Rotate fields +- [x] Label Home (^LH) - Set label home position +- [x] Label Reverse Print (^LR) - Reverse entire label + +### Storage & Templates +- [x] Download Graphics (~DG) - Store graphic to memory +- [x] Download Objects (~DY) - Store objects/fonts to memory +- [x] Download Format (^DF) - Store label template +- [x] Recall Format (^XF) - Recall label template + +### Control Elements +- [x] Comment (^FX) +- [x] Barcode Field Default (^BY) - Set barcode module width + +## Unsupported Label Elements + +### Graphic Elements +- [ ] Graphic Ellipse (^GE): Implemented in Label project, missing drawer +- [ ] Graphic Symbol (^GS): Implemented in Label project, missing drawer +- [ ] Graphic Diagonal Line (^GD): Implemented in Label project, missing drawer + # Open Tasks - Barcodes scaling @@ -26,24 +112,6 @@ foreach (var labelInfo in analyzeInfo.LabelInfos) # Adding Barcode support Also applies to other "drawables", like shapes and graphics. -## Common barcodes still missing support -### 1D -- [ ] Code 93: Supported by Xzing.net -- [ ] MSI: Supported by Xzing.net -- [ ] Codabar/NW7: Supported by Xzing.net -- [ ] Databar/RSS-14: Not supported by Xzing.net -- [ ] [Code 11](https://web.archive.org/web/20070202060711/http://www.barcodeisland.com/code11.phtml): Not supported by Xzing.net, simple to implement - -### 2D -- [ ] Maxicode: Not supported by Xzing.net, required for UPS labels -- [ ] Aztec: Supported by Xzing.net -- [ ] Micro pdf417: Not supported by Xzing.net - - ascii data only - - appears to be a subset of pdf417 -- [ ] Micro QrCode: Not supported by Xzing.net - - appears to be a subset of QrCode -- [ ] Composite: Not supported by Xzing.net, simple to implement - ## Examples - [EAN Barcode](https://github.com/BinaryKits/BinaryKits.Zpl/commit/3fac409732e19be9e047ee71f942ba1f68c6fa5c) - [Datamatrix Barcode](https://github.com/BinaryKits/BinaryKits.Zpl/commit/f79d01512eee7e3d16246e932877ca6d4aa4e306) diff --git a/src/BinaryKits.Zpl.Viewer/Symologies/MaxiCodeSymbology.cs b/src/BinaryKits.Zpl.Viewer/Symologies/MaxiCodeSymbology.cs new file mode 100644 index 00000000..bbd3712e --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Symologies/MaxiCodeSymbology.cs @@ -0,0 +1,705 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace BinaryKits.Zpl.Viewer.Symologies +{ + public static class MaxiCodeSymbology + { + private static readonly Regex mode2Regex = new(@"^(?)(?\d{3})(?\d{3})(?\d{1,9})", RegexOptions.Compiled); + private static readonly Regex mode2GsRegex = new(@"^(?\[\)>\x1e01\x1d(?\d\d))(?\d{1,9})\x1d(?\d{3})\x1d(?\d{3})\x1d", RegexOptions.Compiled); + private static readonly Regex mode3Regex = new(@"^(?)(?\d{3})(?\d{3})(?[ 0-9A-Z]{1,6})", RegexOptions.Compiled); + private static readonly Regex mode3GsRegex = new(@"^(?\[\)>\x1e01\x1d(?\d\d))(?[ 0-9A-Z]{1,6})\x1d(?\d{3})\x1d(?\d{3})\x1d", RegexOptions.Compiled); + + private static readonly Regex numericShiftRegex = new(@"^\d{9}", RegexOptions.Compiled); + private static readonly Regex codeARegex = new(@"^[\r\x1c-\x1e ""-:A-Z]+", RegexOptions.Compiled); + private static readonly Regex codeBRegex = new(@"^[\x1c-\x1e !,./:-@\[-\x7f]+", RegexOptions.Compiled); + //private static readonly Regex codeCRegex = new(@"^[\x1c-\x1e \x80-\x89\xaa\xac\xb1-\xb3\xb5\xb9\xba\xbc-\xbe\xc0-\xdf]+", RegexOptions.Compiled); + //private static readonly Regex codeDRegex = new(@"^[\x1c-\x1e \x8a-\x94\xa1\xa8\xab\xaf\xb0\xb4\xb7\xb8\xbb\xbf\xe0-\xff]+", RegexOptions.Compiled); + //private static readonly Regex codeERegex = new(@"^[\x00- \x95-\xa0\xa2-\xa7\xa9\xad\xae\xb6]+", RegexOptions.Compiled); + + private static readonly int[] ec10Poly = [1, 31, 28, 39, 42, 57, 2, 3, 49, 44, 46]; + private static readonly int[] ec20Poly = [1, 23, 44, 11, 33, 27, 8, 22, 37, 57, 36, 15, 48, 22, 17, 38, 33, 31, 19, 23, 59]; + private static readonly int[] ec28Poly = [1, 22, 45, 53, 10, 41, 55, 35, 10, 22, 29, 23, 13, 61, 45, 34, 55, 40, 37, 46, 49, 34, 41, 9, 43, 7, 20, 11, 28]; + + private enum MaxiCodeCodeSet + { + CodeSetA, + CodeSetB, + CodeSetC, + CodeSetD, + CodeSetE + } + + private enum CodewordType + { + Right = 0, + Left = 1, + Down = 2, + Irregular = 3 + } + + private struct Codeword + { + public CodewordType type; + public int msb; + public int[] offsets; + }; + + private static readonly Dictionary offsets = new() { + { CodewordType.Right, [0, -1, 30, 29, 59, 58] }, + { CodewordType.Left, [0, -1, 29, 28, 59, 58] }, + { CodewordType.Down, [0, 30, 29, 59, 89, 88] } + }; + + private static readonly int[] orientationPatterns = [ + // mode mark + 28, 29, + // top left + 276, 277, 306, + // middle left + 450, 480, + // middle right + 492, 522, + // bottom left + 659, 689, + // bottom right + 666, 696 + ]; + + private static readonly Codeword[] codewords = [ + // primary message + // 1-9 + new Codeword { type = CodewordType.Irregular, msb = 462, offsets = [0, 59, -180, -151, -120, -121] }, + new Codeword { type = CodewordType.Irregular, msb = 662, offsets = [0, -1, 30, 29, -25, 3] }, + new Codeword { type = CodewordType.Irregular, msb = 279, offsets = [0, -1, 29, 28, 85, 321] }, + new Codeword { type = CodewordType.Irregular, msb = 608, offsets = [0, -235, -236, -205, -206, -176] }, + new Codeword { type = CodewordType.Irregular, msb = 694, offsets = [0, -1, -144, -114, -115, -85] }, + new Codeword { type = CodewordType.Irregular, msb = 451, offsets = [0, 59, 179, 239, 213, 212] }, + new Codeword { type = CodewordType.Irregular, msb = 281, offsets = [0, -1, 29, 28, 24, 54] }, + new Codeword { type = CodewordType.Irregular, msb = 523, offsets = [0, -238, -239, -209, -179, -180] }, + new Codeword { type = CodewordType.Irregular, msb = 449, offsets = [0, 29, 60, 59, 15, 14] }, + // 10-20 + new Codeword { type = CodewordType.Right, msb = 363 }, + new Codeword { type = CodewordType.Right, msb = 540 }, + new Codeword { type = CodewordType.Left, msb = 639 }, + new Codeword { type = CodewordType.Left, msb = 629 }, + new Codeword { type = CodewordType.Left, msb = 275 }, + new Codeword { type = CodewordType.Right, msb = 375 }, + new Codeword { type = CodewordType.Right, msb = 552 }, + new Codeword { type = CodewordType.Right, msb = 538 }, + new Codeword { type = CodewordType.Right, msb = 361 }, + new Codeword { type = CodewordType.Left, msb = 287 }, + new Codeword { type = CodewordType.Left, msb = 641 }, + // secondary message + // 21-34 + new Codeword { type = CodewordType.Right, msb = 1 }, + new Codeword { type = CodewordType.Right, msb = 3 }, + new Codeword { type = CodewordType.Right, msb = 5 }, + new Codeword { type = CodewordType.Right, msb = 7 }, + new Codeword { type = CodewordType.Right, msb = 9 }, + new Codeword { type = CodewordType.Right, msb = 11 }, + new Codeword { type = CodewordType.Right, msb = 13 }, + new Codeword { type = CodewordType.Right, msb = 15 }, + new Codeword { type = CodewordType.Right, msb = 17 }, + new Codeword { type = CodewordType.Right, msb = 19 }, + new Codeword { type = CodewordType.Right, msb = 21 }, + new Codeword { type = CodewordType.Right, msb = 23 }, + new Codeword { type = CodewordType.Right, msb = 25 }, + new Codeword { type = CodewordType.Right, msb = 27 }, + // 35-48 + new Codeword { type = CodewordType.Left, msb = 116 }, + new Codeword { type = CodewordType.Left, msb = 114 }, + new Codeword { type = CodewordType.Left, msb = 112 }, + new Codeword { type = CodewordType.Left, msb = 110 }, + new Codeword { type = CodewordType.Left, msb = 108 }, + new Codeword { type = CodewordType.Left, msb = 106 }, + new Codeword { type = CodewordType.Left, msb = 104 }, + new Codeword { type = CodewordType.Left, msb = 102 }, + new Codeword { type = CodewordType.Left, msb = 100 }, + new Codeword { type = CodewordType.Left, msb = 98 }, + new Codeword { type = CodewordType.Left, msb = 96 }, + new Codeword { type = CodewordType.Left, msb = 94 }, + new Codeword { type = CodewordType.Left, msb = 92 }, + new Codeword { type = CodewordType.Left, msb = 90 }, + // 49-62 + new Codeword { type = CodewordType.Right, msb = 178 }, + new Codeword { type = CodewordType.Right, msb = 180 }, + new Codeword { type = CodewordType.Right, msb = 182 }, + new Codeword { type = CodewordType.Right, msb = 184 }, + new Codeword { type = CodewordType.Right, msb = 186 }, + new Codeword { type = CodewordType.Right, msb = 188 }, + new Codeword { type = CodewordType.Right, msb = 190 }, + new Codeword { type = CodewordType.Right, msb = 192 }, + new Codeword { type = CodewordType.Right, msb = 194 }, + new Codeword { type = CodewordType.Right, msb = 196 }, + new Codeword { type = CodewordType.Right, msb = 198 }, + new Codeword { type = CodewordType.Right, msb = 200 }, + new Codeword { type = CodewordType.Right, msb = 202 }, + new Codeword { type = CodewordType.Right, msb = 204 }, + // 63-69 + new Codeword { type = CodewordType.Left, msb = 293 }, + new Codeword { type = CodewordType.Left, msb = 291 }, + new Codeword { type = CodewordType.Left, msb = 289 }, + new Codeword { type = CodewordType.Left, msb = 273 }, + new Codeword { type = CodewordType.Left, msb = 271 }, + new Codeword { type = CodewordType.Left, msb = 269 }, + new Codeword { type = CodewordType.Left, msb = 267 }, + // 70-75 + new Codeword { type = CodewordType.Right, msb = 355 }, + new Codeword { type = CodewordType.Right, msb = 357 }, + new Codeword { type = CodewordType.Right, msb = 359 }, + new Codeword { type = CodewordType.Right, msb = 377 }, + new Codeword { type = CodewordType.Right, msb = 379 }, + new Codeword { type = CodewordType.Right, msb = 381 }, + // 76-81 + new Codeword { type = CodewordType.Left, msb = 470 }, + new Codeword { type = CodewordType.Left, msb = 468 }, + new Codeword { type = CodewordType.Left, msb = 466 }, + new Codeword { type = CodewordType.Left, msb = 448 }, + new Codeword { type = CodewordType.Left, msb = 446 }, + new Codeword { type = CodewordType.Left, msb = 444 }, + // 82-87 + new Codeword { type = CodewordType.Right, msb = 532 }, + new Codeword { type = CodewordType.Right, msb = 534 }, + new Codeword { type = CodewordType.Right, msb = 536 }, + new Codeword { type = CodewordType.Right, msb = 554 }, + new Codeword { type = CodewordType.Right, msb = 556 }, + new Codeword { type = CodewordType.Right, msb = 558 }, + // 88-94 + new Codeword { type = CodewordType.Left, msb = 647 }, + new Codeword { type = CodewordType.Left, msb = 645 }, + new Codeword { type = CodewordType.Left, msb = 643 }, + new Codeword { type = CodewordType.Left, msb = 627 }, + new Codeword { type = CodewordType.Left, msb = 625 }, + new Codeword { type = CodewordType.Left, msb = 623 }, + new Codeword { type = CodewordType.Left, msb = 621 }, + // 95-108 + new Codeword { type = CodewordType.Right, msb = 709 }, + new Codeword { type = CodewordType.Right, msb = 711 }, + new Codeword { type = CodewordType.Right, msb = 713 }, + new Codeword { type = CodewordType.Right, msb = 715 }, + new Codeword { type = CodewordType.Right, msb = 717 }, + new Codeword { type = CodewordType.Right, msb = 719 }, + new Codeword { type = CodewordType.Right, msb = 721 }, + new Codeword { type = CodewordType.Right, msb = 723 }, + new Codeword { type = CodewordType.Right, msb = 725 }, + new Codeword { type = CodewordType.Right, msb = 727 }, + new Codeword { type = CodewordType.Right, msb = 729 }, + new Codeword { type = CodewordType.Right, msb = 731 }, + new Codeword { type = CodewordType.Right, msb = 733 }, + new Codeword { type = CodewordType.Right, msb = 735 }, + // 109-122 + new Codeword { type = CodewordType.Left, msb = 824 }, + new Codeword { type = CodewordType.Left, msb = 822 }, + new Codeword { type = CodewordType.Left, msb = 820 }, + new Codeword { type = CodewordType.Left, msb = 818 }, + new Codeword { type = CodewordType.Left, msb = 816 }, + new Codeword { type = CodewordType.Left, msb = 814 }, + new Codeword { type = CodewordType.Left, msb = 812 }, + new Codeword { type = CodewordType.Left, msb = 810 }, + new Codeword { type = CodewordType.Left, msb = 808 }, + new Codeword { type = CodewordType.Left, msb = 806 }, + new Codeword { type = CodewordType.Left, msb = 804 }, + new Codeword { type = CodewordType.Left, msb = 802 }, + new Codeword { type = CodewordType.Left, msb = 800 }, + new Codeword { type = CodewordType.Left, msb = 798 }, + // 123-136 + new Codeword { type = CodewordType.Right, msb = 886 }, + new Codeword { type = CodewordType.Right, msb = 888 }, + new Codeword { type = CodewordType.Right, msb = 890 }, + new Codeword { type = CodewordType.Right, msb = 892 }, + new Codeword { type = CodewordType.Right, msb = 894 }, + new Codeword { type = CodewordType.Right, msb = 896 }, + new Codeword { type = CodewordType.Right, msb = 898 }, + new Codeword { type = CodewordType.Right, msb = 900 }, + new Codeword { type = CodewordType.Right, msb = 902 }, + new Codeword { type = CodewordType.Right, msb = 904 }, + new Codeword { type = CodewordType.Right, msb = 906 }, + new Codeword { type = CodewordType.Right, msb = 908 }, + new Codeword { type = CodewordType.Right, msb = 910 }, + new Codeword { type = CodewordType.Right, msb = 912 }, + // 137-144 + new Codeword { type = CodewordType.Down, msb = 58 }, + new Codeword { type = CodewordType.Down, msb = 176 }, + new Codeword { type = CodewordType.Down, msb = 294 }, + new Codeword { type = CodewordType.Down, msb = 412 }, + new Codeword { type = CodewordType.Down, msb = 530 }, + new Codeword { type = CodewordType.Down, msb = 648 }, + new Codeword { type = CodewordType.Down, msb = 766 }, + new Codeword { type = CodewordType.Down, msb = 884 }, + ]; + + private const string ECI = "ECI"; + private const string NS = "NS"; + private const string PAD = "PAD"; + private const string PAD1 = "PAD1"; + private const string PAD2 = "PAD2"; + + private const string SHIFT_A = "SHIFT_A"; + private const string SHIFT_B = "SHIFT_B"; + private const string SHIFT_C = "SHIFT_C"; + private const string SHIFT_D = "SHIFT_D"; + private const string SHIFT_E = "SHIFT_E"; + + private const string SHIFT_2A = "SHIFT_2A"; + private const string SHIFT_3A = "SHIFT_3A"; + + private const string LATCH_A = "LATCH_A"; + private const string LATCH_B = "LATCH_B"; + + private const string LOCK_IN_C = "LOCK_IN_C"; + private const string LOCK_IN_D = "LOCK_IN_D"; + private const string LOCK_IN_E = "LOCK_IN_E"; + + private static readonly Dictionary codeAMap; + private static readonly Dictionary codeBMap; + private static readonly Dictionary codeCMap; + private static readonly Dictionary codeDMap; + private static readonly Dictionary codeEMap; + + static MaxiCodeSymbology() + { + var codeSetTable = new[] + { + new { Value = 0, A = "\x0d", B = "`", C = "\xc0", D = "\xe0", E = "\x00" }, + new { Value = 1, A = "A", B = "a", C = "\xc1", D = "\xe1", E = "\x01" }, + new { Value = 2, A = "B", B = "b", C = "\xc2", D = "\xe2", E = "\x02" }, + new { Value = 3, A = "C", B = "c", C = "\xc3", D = "\xe3", E = "\x03" }, + new { Value = 4, A = "D", B = "d", C = "\xc4", D = "\xe4", E = "\x04" }, + new { Value = 5, A = "E", B = "e", C = "\xc5", D = "\xe5", E = "\x05" }, + new { Value = 6, A = "F", B = "f", C = "\xc6", D = "\xe6", E = "\x06" }, + new { Value = 7, A = "G", B = "g", C = "\xc7", D = "\xe7", E = "\x07" }, + new { Value = 8, A = "H", B = "h", C = "\xc8", D = "\xe8", E = "\x08" }, + new { Value = 9, A = "I", B = "i", C = "\xc9", D = "\xe9", E = "\x09" }, + new { Value = 10, A = "J", B = "j", C = "\xca", D = "\xea", E = "\x0a" }, + new { Value = 11, A = "K", B = "k", C = "\xcb", D = "\xeb", E = "\x0b" }, + new { Value = 12, A = "L", B = "l", C = "\xcc", D = "\xec", E = "\x0c" }, + new { Value = 13, A = "M", B = "m", C = "\xcd", D = "\xed", E = "\x0d" }, + new { Value = 14, A = "N", B = "n", C = "\xce", D = "\xee", E = "\x0e" }, + new { Value = 15, A = "O", B = "o", C = "\xcf", D = "\xef", E = "\x0f" }, + new { Value = 16, A = "P", B = "p", C = "\xd0", D = "\xf0", E = "\x10" }, + new { Value = 17, A = "Q", B = "q", C = "\xd1", D = "\xf1", E = "\x11" }, + new { Value = 18, A = "R", B = "r", C = "\xd2", D = "\xf2", E = "\x12" }, + new { Value = 19, A = "S", B = "s", C = "\xd3", D = "\xf3", E = "\x13" }, + new { Value = 20, A = "T", B = "t", C = "\xd4", D = "\xf4", E = "\x14" }, + new { Value = 21, A = "U", B = "u", C = "\xd5", D = "\xf5", E = "\x15" }, + new { Value = 22, A = "V", B = "v", C = "\xd6", D = "\xf6", E = "\x16" }, + new { Value = 23, A = "W", B = "w", C = "\xd7", D = "\xf7", E = "\x17" }, + new { Value = 24, A = "X", B = "x", C = "\xd8", D = "\xf8", E = "\x18" }, + new { Value = 25, A = "Y", B = "y", C = "\xd9", D = "\xf9", E = "\x19" }, + new { Value = 26, A = "Z", B = "z", C = "\xda", D = "\xfa", E = "\x1a" }, + new { Value = 27, A = ECI, B = ECI, C = ECI, D = ECI, E = ECI }, + new { Value = 28, A = "\x1c", B = "\x1c", C = "\x1c", D = "\x1c", E = PAD }, + new { Value = 29, A = "\x1d", B = "\x1d", C = "\x1d", D = "\x1d", E = PAD1 }, + new { Value = 30, A = "\x1e", B = "\x1e", C = "\x1e", D = "\x1e", E = "\x1b" }, + new { Value = 31, A = NS, B = NS, C = NS, D = NS, E = NS }, + new { Value = 32, A = " ", B = "{", C = "\xdb", D = "\xfb", E = "\x1c" }, + new { Value = 33, A = PAD, B = PAD, C = "\xdc", D = "\xfc", E = "\x1d" }, + new { Value = 34, A = "\"", B = "}", C = "\xdd", D = "\xfd", E = "\x1e" }, + new { Value = 35, A = "#", B = "~", C = "\xde", D = "\xfe", E = "\x1f" }, + new { Value = 36, A = "$", B = "\x7f", C = "\xdf", D = "\xff", E = "\x9f" }, + new { Value = 37, A = "%", B = ";", C = "\xaa", D = "\xa1", E = "\xa0" }, + new { Value = 38, A = "&", B = "<", C = "\xac", D = "\xa8", E = "\xa2" }, + new { Value = 39, A = "'", B = "=", C = "\xb1", D = "\xab", E = "\xa3" }, + new { Value = 40, A = "(", B = ">", C = "\xb2", D = "\xaf", E = "\xa4" }, + new { Value = 41, A = ")", B = "?", C = "\xb3", D = "\xb0", E = "\xa5" }, + new { Value = 42, A = "*", B = "[", C = "\xb5", D = "\xb4", E = "\xa6" }, + new { Value = 43, A = "+", B = "\\", C = "\xb9", D = "\xb7", E = "\xa7" }, + new { Value = 44, A = ",", B = "]", C = "\xba", D = "\xb8", E = "\xa9" }, + new { Value = 45, A = "-", B = "^", C = "\xbc", D = "\xbb", E = "\xad" }, + new { Value = 46, A = ".", B = "_", C = "\xbd", D = "\xbf", E = "\xae" }, + new { Value = 47, A = "/", B = " ", C = "\xbe", D = "\x8a", E = "\xb6" }, + new { Value = 48, A = "0", B = ",", C = "\x80", D = "\x8b", E = "\x95" }, + new { Value = 49, A = "1", B = ".", C = "\x81", D = "\x8c", E = "\x96" }, + new { Value = 50, A = "2", B = "/", C = "\x82", D = "\x8d", E = "\x97" }, + new { Value = 51, A = "3", B = ":", C = "\x83", D = "\x8e", E = "\x98" }, + new { Value = 52, A = "4", B = "@", C = "\x84", D = "\x8f", E = "\x99" }, + new { Value = 53, A = "5", B = "!", C = "\x85", D = "\x90", E = "\x9a" }, + new { Value = 54, A = "6", B = "|", C = "\x86", D = "\x91", E = "\x9b" }, + new { Value = 55, A = "7", B = PAD1, C = "\x87", D = "\x92", E = "\x9c" }, + new { Value = 56, A = "8", B = SHIFT_2A, C = "\x88", D = "\x93", E = "\x9d" }, + new { Value = 57, A = "9", B = SHIFT_3A, C = "\x89", D = "\x94", E = "\x9e" }, + new { Value = 58, A = ":", B = PAD2, C = LATCH_A, D = LATCH_A, E = LATCH_A }, + new { Value = 59, A = SHIFT_B, B = SHIFT_A, C = " ", D = " ", E = " " }, + new { Value = 60, A = SHIFT_C, B = SHIFT_C, C = LOCK_IN_C, D = SHIFT_C, E = SHIFT_C }, + new { Value = 61, A = SHIFT_D, B = SHIFT_D, C = SHIFT_D, D = LOCK_IN_D, E = SHIFT_D }, + new { Value = 62, A = SHIFT_E, B = SHIFT_E, C = SHIFT_E, D = SHIFT_E, E = LOCK_IN_E }, + new { Value = 63, A = LATCH_B, B = LATCH_A, C = LATCH_B, D = LATCH_B, E = LATCH_B }, + }; + + codeAMap = codeSetTable.ToDictionary(item => item.A, item => item.Value); + codeBMap = codeSetTable.ToDictionary(item => item.B, item => item.Value); + codeCMap = codeSetTable.ToDictionary(item => item.C, item => item.Value); + codeDMap = codeSetTable.ToDictionary(item => item.D, item => item.Value); + codeEMap = codeSetTable.ToDictionary(item => item.E, item => item.Value); + } + + public static bool[] Encode(string content, int mode) + { + bool[] result = new bool[974]; + foreach (int idx in orientationPatterns) + { + result[idx] = true; + } + + List data = Analyze(content, mode); + + foreach ((int val, int idx) in data.Select((v, i) => (v, i))) + { + Codeword codeword = codewords[idx]; + int[] offs = codeword.offsets; + if (codeword.type != CodewordType.Irregular) + { + offs = offsets[codeword.type]; + } + + for (int i = 0; i < 6; i++) + { + result[codeword.msb + offs[i]] = (val & (1 << 5 - i)) > 0; + } + } + + return result; + } + + private static List Analyze(string content, int mode) + { + List data = []; + bool eec = false; + MaxiCodeCodeSet codeSet = MaxiCodeCodeSet.CodeSetA; + Dictionary codeMap = codeAMap; + + if (mode == 2) + { + Match mode2Match = mode2Regex.Match(content); + + if (!mode2Match.Success) + { + mode2Match = mode2GsRegex.Match(content); + } + + if (!mode2Match.Success) + { + // invalid mode 2 data, convert to mode 4 + return Analyze(content, 4); + } + + int service = int.Parse(mode2Match.Groups["service"].Value); + int country = int.Parse(mode2Match.Groups["country"].Value); + string zip = mode2Match.Groups["zip"].Value; + if (country == 840) + { + zip = zip.PadRight(9, '0'); + } + + int ziplen = zip.Length; + int zipval = int.Parse(zip); + + // ISO/IEC 12023:2000 pp. 26 + data.Add(((zipval & 3) << 4) | mode); // 1-6 + + data.Add((zipval >> 2) & 63); // 7-12 + data.Add((zipval >> 8) & 63); // 13-18 + data.Add((zipval >> 14) & 63); // 19-24 + data.Add((zipval >> 20) & 63); // 25-30 + + data.Add(((ziplen & 3) << 4) | (zipval >> 26)); // 31-36 + data.Add(((country & 3) << 4) | (ziplen >> 2)); // 37-42 + data.Add((country >> 2) & 63); // 43-48 + + data.Add(((service & 15) << 2) | (country >> 8)); // 49-54 + data.Add(service >> 4); // 60-55 + + content = mode2Match.Groups["preamble"].Value + content.Substring(mode2Match.Length); + } + else if (mode == 3) + { + Match mode3Match = mode3Regex.Match(content); + + if (!mode3Match.Success) + { + mode3Match = mode3GsRegex.Match(content); + } + + if (!mode3Match.Success) + { + // invalid mode 3 data, convert to mode 4 + return Analyze(content, 4); + } + + int service = int.Parse(mode3Match.Groups["service"].Value); + int country = int.Parse(mode3Match.Groups["country"].Value); + string zip = mode3Match.Groups["zip"].Value; + if (zip.Length < 6) + { + zip = zip.PadRight(6); + } + + long zipval = 0; + for (int i = 0; i < 6; i++) + { + zipval = zipval << 6 | (long)codeAMap[zip.Substring(i, 1)]; + } + + // ISO/IEC 12023:2000 pp. 26 + data.Add((int)((zipval & 3) << 4) | mode); // 1-6 + + data.Add((int)((zipval >> 2) & 63)); // 7-12 + data.Add((int)((zipval >> 8) & 63)); // 13-18 + data.Add((int)((zipval >> 14) & 63)); // 19-24 + data.Add((int)((zipval >> 20) & 63)); // 25-30 + data.Add((int)((zipval >> 26) & 63)); // 31-36 + + data.Add(((country & 3) << 4) | (int)((zipval >> 32) & 15)); // 37-42 + data.Add((country >> 2) & 63); // 43-48 + + data.Add(((service & 15) << 2) | (country >> 8)); // 49-54 + data.Add(service >> 4); // 60-55 + + content = mode3Match.Groups["preamble"].Value + content.Substring(mode3Match.Length); + } + else + { + data.Add(mode); + eec = mode == 5; + } + + while (content.Length > 0) + { + if (data.Count == 10) + { + data.AddRange(ComputeReadSolomon(data, ec10Poly)); + } + + if (numericShiftRegex.IsMatch(content)) + { + data.Add(codeMap[NS]); + int value = int.Parse(content.Substring(0, 9)); + content = content.Substring(9); + for (int i = 24; i >= 0; i -= 6) + { + data.Add((value >> i) & 63); + } + } + else + { + int value; + string c = StringInfo.GetNextTextElement(content); + StringInfo stringInfo = new(content); + if (stringInfo.LengthInTextElements > 1) + { + content = stringInfo.SubstringByTextElements(1); + } + else + { + content = string.Empty; + } + + if (codeMap.TryGetValue(c, out value)) + { + data.Add(value); + } + else if (codeSet == MaxiCodeCodeSet.CodeSetA && codeBMap.ContainsKey(c)) + { + if (codeBRegex.IsMatch(content) && !codeARegex.IsMatch(content)) + { + data.Add(codeMap[LATCH_B]); + codeSet = MaxiCodeCodeSet.CodeSetB; + codeMap = codeBMap; + data.Add(codeMap[c]); + } + else + { + data.Add(codeMap[SHIFT_B]); + data.Add(codeBMap[c]); + } + } + else if (codeSet == MaxiCodeCodeSet.CodeSetB && codeAMap.ContainsKey(c)) + { + Match codeAMatch = codeARegex.Match(content); + if (codeAMatch.Success) + { + if (codeAMatch.Length >= 3) + { + data.Add(codeMap[LATCH_A]); + codeSet = MaxiCodeCodeSet.CodeSetA; + codeMap = codeAMap; + data.Add(codeMap[c]); + } + else if (codeAMatch.Length == 2) + { + data.Add(codeMap[SHIFT_3A]); + data.Add(codeAMap[c]); + data.Add(codeAMap[content.Substring(0, 1)]); + data.Add(codeAMap[content.Substring(1, 1)]); + content = content.Substring(2); + } + else if (codeAMatch.Length == 1) + { + data.Add(codeMap[SHIFT_2A]); + data.Add(codeAMap[c]); + data.Add(codeAMap[content.Substring(0, 1)]); + content = content.Substring(1); + } + } + else + { + data.Add(codeMap[SHIFT_A]); + data.Add(codeAMap[c]); + } + } + else if (codeCMap.TryGetValue(c, out value)) + { + // TODO: lock in if more than one character + data.Add(codeMap[SHIFT_C]); + data.Add(value); + } + else if (codeDMap.TryGetValue(c, out value)) + { + // TODO: lock in if more than one character + data.Add(codeMap[SHIFT_D]); + data.Add(value); + } + else if (codeEMap.TryGetValue(c, out value)) + { + // TODO: lock in if more than one character + data.Add(codeMap[SHIFT_E]); + data.Add(value); + } + else + { + // non ISO-8859-1 character, drop + // TODO: change ECI + } + } + } + + if (data.Count <= 10) + { + data.AddRange(Enumerable.Repeat(codeMap[PAD], 10 - data.Count)); + data.AddRange(ComputeReadSolomon(data, ec10Poly)); + } + + if (eec) + { + if (data.Count <= 88) + { + data.AddRange(Enumerable.Repeat(codeMap[PAD], 88 - data.Count)); + } + else + { + // too much data for EEC + // if mode 5, convert to mode 4, else truncate + if (mode == 5) + { + mode = 4; + eec = false; + data[0] = mode; + data.RemoveRange(10, 10); + data.InsertRange(10, ComputeReadSolomon(data.GetRange(0, 10), ec10Poly)); + } + else + { + data.RemoveRange(88, data.Count - 88); + } + } + } + + if (!eec) + { + if (data.Count <= 104) + { + data.AddRange(Enumerable.Repeat(codeMap[PAD], 104 - data.Count)); + } + else + { + // too much data for SEC, truncate + data.RemoveRange(104, data.Count - 104); + } + + } + + List odds = []; + List evens = []; + for (int i = 20; i < data.Count; i += 2) + { + odds.Add(data[i]); + evens.Add(data[i + 1]); + } + + List oddCorrection; + List evenCorrection; + if (eec) + { + oddCorrection = ComputeReadSolomon(odds, ec28Poly); + evenCorrection = ComputeReadSolomon(evens, ec28Poly); + } + else + { + oddCorrection = ComputeReadSolomon(odds, ec20Poly); + evenCorrection = ComputeReadSolomon(evens, ec20Poly); + } + + for (int i = 0; i < oddCorrection.Count; i++) + { + data.Add(oddCorrection[i]); + data.Add(evenCorrection[i]); + } + + return data; + } + + private static List ComputeReadSolomon(List data, int[] ecPoly) + { + int ecLen = ecPoly.Length - 1; + List quotient = GF64PolynomalDivision([.. data, .. Enumerable.Repeat(0, ecLen)], ecPoly); + return quotient.GetRange(quotient.Count - ecLen, ecLen); + } + + private static List GF64PolynomalDivision(List dividend, int[] divisor) + { + int normalizer = divisor[0]; + + for (int i = 0; i < dividend.Count - (divisor.Length - 1); i++) + { + dividend[i] /= normalizer; + + int coeff = dividend[i]; + if (coeff != 0) + { + for (int j = 1; j < divisor.Length; j++) + { + dividend[i + j] ^= GF64Multiply(divisor[j], coeff); + } + } + } + + return dividend; + } + + private static int GF64Multiply(int a, int b) + { + int product = 0; + while (a != 0 && b != 0) + { + if ((b & 1) > 0) + { + product ^= a; + } + + a <<= 1; + if ((a & 64) > 0) + { + a ^= 67; // x^6 + x + 1 + } + + b >>= 1; + } + + return product; + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Symologies/UpcExtensionSymbology.cs b/src/BinaryKits.Zpl.Viewer/Symologies/UpcExtensionSymbology.cs new file mode 100644 index 00000000..4a0fae4e --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Symologies/UpcExtensionSymbology.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BinaryKits.Zpl.Viewer.Symologies +{ + public class UpcExtensionSymbology + { + + private static readonly Dictionary patternMap; + private static readonly Dictionary parity5Map; + + static UpcExtensionSymbology() + { + var codeSetTable = new[] { + new { Value = 0, Pattern = new int[] { 0b0001101, 0b0100111 }, Parity5 = 0b11000 }, + new { Value = 1, Pattern = new int[] { 0b0011001, 0b0110011 }, Parity5 = 0b10100 }, + new { Value = 2, Pattern = new int[] { 0b0010011, 0b0011011 }, Parity5 = 0b10010 }, + new { Value = 3, Pattern = new int[] { 0b0111101, 0b0100001 }, Parity5 = 0b10001 }, + new { Value = 4, Pattern = new int[] { 0b0100011, 0b0011101 }, Parity5 = 0b01100 }, + new { Value = 5, Pattern = new int[] { 0b0110001, 0b0111001 }, Parity5 = 0b00110 }, + new { Value = 6, Pattern = new int[] { 0b0101111, 0b0000101 }, Parity5 = 0b00011 }, + new { Value = 7, Pattern = new int[] { 0b0111011, 0b0010001 }, Parity5 = 0b01010 }, + new { Value = 8, Pattern = new int[] { 0b0110111, 0b0001001 }, Parity5 = 0b01001 }, + new { Value = 9, Pattern = new int[] { 0b0001011, 0b0010111 }, Parity5 = 0b00101 } + }; + + patternMap = codeSetTable.ToDictionary(item => item.Value, item => item.Pattern); + parity5Map = codeSetTable.ToDictionary(item => item.Value, item => item.Parity5); + } + + public static bool[] Encode(string content) + { + if (content == null) + { + throw new ArgumentNullException("content"); + } + else if (content.Length != 2 && content.Length != 5) + { + throw new ArgumentException("Barcode content length must be 2 or 5 for UPC Extension."); + } + + if (!int.TryParse(content, out int value)) + { + throw new ArgumentException("Barcode content must be numeric for UPC Extension."); + } + + List result = []; + int type = content.Length; + int[] digits = IntToDigits(value, type); + bool[] parities = []; + + if (type == 2) + { + parities = IntToBitArray(value % 4, type); + } + else + { + int parity = 0; + int coeff = 3; + foreach(int digit in digits) + { + parity += digit * coeff; + coeff ^= 10; + } + + parities = IntToBitArray(parity5Map[parity % 10], type); + } + + result.AddRange([true, false, true, true]); + + for (int i = 0; i < type; i++) { + int pattern = patternMap[digits[i]][parities[i] ? 1 : 0]; + result.AddRange(IntToBitArray(pattern, 7)); + + if (i < type - 1) + { + result.AddRange([false, true]); + } + } + + return result.ToArray(); + } + + private static bool[] IntToBitArray(int value, int length) + { + Stack stack = []; + for(int i = 0; i < length; i++) + { + stack.Push((value & 1) == 1); + value >>= 1; + } + + return stack.ToArray(); + } + + private static int[] IntToDigits(int value, int length) + { + Stack stack = []; + for (int i = 0; i < length; i++) + { + stack.Push(value % 10); + value /= 10; + } + + return stack.ToArray(); + } + + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Symologies/ZplCode128Symbology.cs b/src/BinaryKits.Zpl.Viewer/Symologies/ZplCode128Symbology.cs index 85340f51..a500dd2d 100644 --- a/src/BinaryKits.Zpl.Viewer/Symologies/ZplCode128Symbology.cs +++ b/src/BinaryKits.Zpl.Viewer/Symologies/ZplCode128Symbology.cs @@ -13,24 +13,24 @@ public enum Code128CodeSet Code128C = 105 } - public class ZplCode128Symbology + public static class ZplCode128Symbology { // detect Type-C as late as possible // ABC12345 -> START_B A B C 1 CODE_C 23 45 CHECK STOP // and not -> START_B A B C CODE_C 12 34 CODE_B 5 CHECK STOP - private static readonly Regex swtichCRegex = new Regex(@"^\d\d(?:\d\d)+(?!\d)", RegexOptions.Compiled); - private static readonly Regex startCRegex = new Regex(@"^\d{4}", RegexOptions.Compiled); - private static readonly Regex digitPairRegex = new Regex(@"^\d\d", RegexOptions.Compiled); + private static readonly Regex swtichCRegex = new(@"^\d\d(?:\d\d)+(?!\d)", RegexOptions.Compiled); + private static readonly Regex startCRegex = new(@"^\d{4}", RegexOptions.Compiled); + private static readonly Regex digitPairRegex = new(@"^\d\d", RegexOptions.Compiled); // GS1 specific - private static readonly Regex gs1SwitchCRegex = new Regex(@"^\d\d(?:\d\d|>8)+(?!\d)", RegexOptions.Compiled); - private static readonly Regex gs1StartCRegex = new Regex(@"^(?:\d\d|>8){2}", RegexOptions.Compiled); - private static readonly Regex gs1DigitPairRegex = new Regex(@"^(?:\d\d|>8)", RegexOptions.Compiled); - private static readonly Regex fnc1Regex = new Regex(@"^>8", RegexOptions.Compiled); + private static readonly Regex gs1SwitchCRegex = new(@"^\d\d(?:\d\d|>8)+(?!\d)", RegexOptions.Compiled); + private static readonly Regex gs1StartCRegex = new(@"^(?:\d\d|>8){2}", RegexOptions.Compiled); + private static readonly Regex gs1DigitPairRegex = new(@"^(?:\d\d|>8)", RegexOptions.Compiled); + private static readonly Regex fnc1Regex = new(@"^>8", RegexOptions.Compiled); - private static readonly Regex startCodeRegex = new Regex(@"^(>[9:;])(.+)$", RegexOptions.Compiled); + private static readonly Regex startCodeRegex = new(@"^(>[9:;])(.+)$", RegexOptions.Compiled); - private static readonly Dictionary invocationMap = new Dictionary() { + private static readonly Dictionary invocationMap = new() { { "><", 62 }, { ">0", 30 }, { ">=", 94 }, @@ -44,13 +44,13 @@ public class ZplCode128Symbology { ">8", 102 } }; - private static readonly Dictionary startCodeMap = new Dictionary() { + private static readonly Dictionary startCodeMap = new() { { ">9", Code128CodeSet.Code128A }, { ">:", Code128CodeSet.Code128B }, { ">;", Code128CodeSet.Code128C } }; - private static readonly Dictionary codeSetCodeMap = new Dictionary() { + private static readonly Dictionary codeSetCodeMap = new() { { Code128CodeSet.Code128A, CODE_A }, { Code128CodeSet.Code128B, CODE_B }, { Code128CodeSet.Code128C, CODE_C } @@ -88,7 +88,8 @@ public class ZplCode128Symbology /// /// /// - static ZplCode128Symbology() { + static ZplCode128Symbology() + { var codeSetTable = new[] { new { Value = 0, A = " ", B = " ", C = "00", Pattern = 0b11011001100 }, @@ -217,9 +218,9 @@ static ZplCode128Symbology() { }; } - public static (List, string) Encode(string content, Code128CodeSet initialCodeSet, bool gs1) + public static (bool[], string) Encode(string content, Code128CodeSet initialCodeSet, bool gs1) { - List result = new List(); + List result = []; List data; string interpretation; if (gs1) @@ -251,7 +252,7 @@ public static (List, string) Encode(string content, Code128CodeSet initial // TODO: magic constant STOP result.AddRange(IntToBitArray(patterns[106])); - return (result, interpretation); + return (result.ToArray(), interpretation); } private static int ComputeChecksum(int[] data) @@ -265,21 +266,21 @@ private static int ComputeChecksum(int[] data) return checksum % 103; } - private static IEnumerable IntToBitArray(int value) + private static bool[] IntToBitArray(int value) { - Stack stack = new Stack(); + Stack stack = []; while (value > 0) { stack.Push((value & 1) == 1); value >>= 1; } - return stack; + return stack.ToArray(); } private static (List, string) Analyze(string content, Code128CodeSet initialCodeSet) { - List data = new(); + List data = []; string interpretation = ""; Code128CodeSet codeSet = initialCodeSet; Match startCodeMatch = startCodeRegex.Match(content); @@ -290,7 +291,7 @@ private static (List, string) Analyze(string content, Code128CodeSet initia startCodeMatch = startCodeRegex.Match(content); } - (var codeChars, var codeMap) = codeMaps[codeSet]; + (string[] codeChars, Dictionary codeMap) = codeMaps[codeSet]; data.Add((int)codeSet); for (int i = 0; i < content.Length; i++) @@ -300,9 +301,9 @@ private static (List, string) Analyze(string content, Code128CodeSet initia { i += 1; symbol += content[i]; - if (invocationMap.ContainsKey(symbol)) + int value; + if (invocationMap.TryGetValue(symbol, out value)) { - int value = invocationMap[symbol]; data.Add(value); string code = codeChars[value]; if (code == CODE_A) @@ -321,12 +322,11 @@ private static (List, string) Analyze(string content, Code128CodeSet initia (codeChars, codeMap) = codeMaps[codeSet]; } } - else if (startCodeMap.ContainsKey(symbol)) + else if (startCodeMap.TryGetValue(symbol, out Code128CodeSet newCodeSet)) { - Code128CodeSet newCodeSet = startCodeMap[symbol]; if (newCodeSet != codeSet) { - int value = codeMap[codeSetCodeMap[newCodeSet]]; + value = codeMap[codeSetCodeMap[newCodeSet]]; data.Add(value); codeSet = newCodeSet; (codeChars, codeMap) = codeMaps[codeSet]; @@ -339,6 +339,7 @@ private static (List, string) Analyze(string content, Code128CodeSet initia } else { + int value; if (codeSet == Code128CodeSet.Code128C) { if (i + 1 < content.Length) @@ -348,18 +349,19 @@ private static (List, string) Analyze(string content, Code128CodeSet initia } else { - int value = codeMap[CODE_B]; + value = codeMap[CODE_B]; data.Add(value); codeSet = Code128CodeSet.Code128B; (codeChars, codeMap) = codeMaps[codeSet]; } } - if (!codeMap.ContainsKey(symbol)) { + if (!codeMap.TryGetValue(symbol, out value)) + { throw new Exception($"Invalid symbol for {codeSet}: {symbol}"); } - data.Add(codeMap[symbol]); + data.Add(value); interpretation += symbol; } } @@ -369,15 +371,16 @@ private static (List, string) Analyze(string content, Code128CodeSet initia private static (List, string) AnalyzeAuto(string content) { - List data = new List(); + List data = []; string interpretation = ""; Code128CodeSet codeSet = Code128CodeSet.Code128B; - var codeMap = codeBMap; + Dictionary codeMap = codeBMap; if (startCRegex.IsMatch(content)) { codeSet = Code128CodeSet.Code128C; codeMap = codeCMap; } + data.Add((int)codeSet); while (content.Length > 0) @@ -417,15 +420,16 @@ private static (List, string) AnalyzeAuto(string content) private static (List, string) AnalyzeGS1(string content) { - List data = new List(); + List data = []; string interpretation = ""; Code128CodeSet codeSet = Code128CodeSet.Code128B; - var codeMap = codeBMap; + Dictionary codeMap = codeBMap; if (gs1StartCRegex.IsMatch(content)) { codeSet = Code128CodeSet.Code128C; codeMap = codeCMap; } + data.Add((int)codeSet); while (content.Length > 0) diff --git a/src/BinaryKits.Zpl.Viewer/VirtualPrinter.cs b/src/BinaryKits.Zpl.Viewer/VirtualPrinter.cs index 5b119927..6580c3d2 100644 --- a/src/BinaryKits.Zpl.Viewer/VirtualPrinter.cs +++ b/src/BinaryKits.Zpl.Viewer/VirtualPrinter.cs @@ -1,5 +1,6 @@ using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Viewer.Models; + using System.Collections.Generic; namespace BinaryKits.Zpl.Viewer @@ -11,6 +12,7 @@ public class VirtualPrinter public FieldDataBase NextElementFieldData { get; private set; } public FieldBlock NextElementFieldBlock { get; private set; } public FieldOrientation FieldOrientation { get; private set; } = FieldOrientation.Normal; + public FieldJustification FieldJustification { get; private set; } = FieldJustification.None; public int FontWidth { get; private set; } = 0; public int FontHeight { get; private set; } = 10; public string FontName { get; private set; } = "0"; @@ -22,7 +24,8 @@ public class VirtualPrinter public FontInfo NextFont { get; private set; } public bool NextElementFieldReverse { get; private set; } - public bool NextElementFieldUseHexadecimalIndicator { get; private set; } + public char? NextElementFieldHexadecimalIndicator { get; private set; } + public FieldJustification NextElementFieldJustification { get; private set; } = FieldJustification.None; public bool LabelReverse { get; private set; } public BarcodeInfo BarcodeInfo { get; private set; } @@ -32,17 +35,17 @@ public class VirtualPrinter public VirtualPrinter() { this.BarcodeInfo = new BarcodeInfo(); - this.Comments = new List(); + this.Comments = []; } - public void SetNextElementPosition(int x, int y, bool calculateFromBottom = false) + public void SetNextElementPosition(int x, int y, bool calculateFromBottom = false, bool useDefaultPosition = false) { - this.NextElementPosition = new LabelPosition(x, y, calculateFromBottom); + this.NextElementPosition = new LabelPosition(x, y, calculateFromBottom, useDefaultPosition); } public void ClearNextElementPosition() { - this.NextElementPosition = new LabelPosition(0, 0, false); + this.NextElementPosition = new LabelPosition(0, 0, false, false); } public void SetNextElementFieldData(FieldDataBase fieldData) @@ -84,27 +87,38 @@ public void SetNextElementFieldReverse() this.NextElementFieldReverse = true; } - public void SetNextElementFieldUseHexadecimalIndicator() + public void ClearNextElementFieldReverse() { - this.NextElementFieldUseHexadecimalIndicator = true; + this.NextElementFieldReverse = false; } - public void SetLabelReverse(bool reverse) + public void SetNextElementFieldHexadecimalIndicator(char replaceChar) { - this.LabelReverse = reverse; + this.NextElementFieldHexadecimalIndicator = replaceChar; } - public void ClearNextElementFieldReverse() + public void ClearNextElementFieldHexadecimalIndicator() { - this.NextElementFieldReverse = false; + this.NextElementFieldHexadecimalIndicator = null; + } + + public void SetNextElementFieldJustification(FieldJustification fieldJustification) + { + this.NextElementFieldJustification = fieldJustification; } - public void ClearNextElementFieldUseHexadecimalIndicator() + public void ClearNextElementFieldJustification() { - this.NextElementFieldUseHexadecimalIndicator = false; + this.NextElementFieldJustification = FieldJustification.None; } - public void SetFieldOrientation(FieldOrientation fieldOrientation) { + public void SetLabelReverse(bool reverse) + { + this.LabelReverse = reverse; + } + + public void SetFieldOrientation(FieldOrientation fieldOrientation) + { this.FieldOrientation = fieldOrientation; if (this.NextFont != null) { @@ -112,6 +126,11 @@ public void SetFieldOrientation(FieldOrientation fieldOrientation) { } } + public void SetFieldJustification(FieldJustification fieldJustification) + { + this.FieldJustification = fieldJustification; + } + public void SetFontWidth(int fontWidth) { this.FontWidth = fontWidth; diff --git a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs index fb79d976..aeefaa41 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs @@ -1,103 +1,107 @@ using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.CommandAnalyzers; using BinaryKits.Zpl.Viewer.Models; + using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using Application.UseCase.ZplToPdf; namespace BinaryKits.Zpl.Viewer { public class ZplAnalyzer : IZplAnalyzer { - private static readonly Regex verticalWhitespaceRegex = new Regex(@"[\n\v\f\r]", RegexOptions.Compiled); + private static readonly Regex verticalWhitespaceRegex = new(@"[\n\v\f\r]", RegexOptions.Compiled); - private readonly VirtualPrinter _virtualPrinter; - private readonly IPrinterStorage _printerStorage; - private readonly IFormatMerger _formatMerger; - private readonly string _labelStartCommand = "^XA"; - private readonly string _labelEndCommand = "^XZ"; + private readonly VirtualPrinter virtualPrinter; + private readonly IPrinterStorage printerStorage; + private readonly IFormatMerger formatMerger; + private readonly string labelStartCommand = "^XA"; + private readonly string labelEndCommand = "^XZ"; public ZplAnalyzer(IPrinterStorage printerStorage, IFormatMerger formatMerger = null) { - this._printerStorage = printerStorage; - this._formatMerger = formatMerger ?? new FormatMerger(); - this._virtualPrinter = new VirtualPrinter(); + this.printerStorage = printerStorage; + this.formatMerger = formatMerger ?? new FormatMerger(); + this.virtualPrinter = new VirtualPrinter(); } public AnalyzeInfo Analyze(string zplData) { - var zplCommands = this.SplitZplCommands(zplData); - var unknownCommands = new List(); - var errors = new List(); + string[] zplCommands = SplitZplCommands(zplData); + List unknownCommands = []; + List errors = []; - var fieldDataAnalyzer = new FieldDataZplCommandAnalyzer(this._virtualPrinter); - var elementAnalyzers = new List - { + FieldDataZplCommandAnalyzer fieldDataAnalyzer = new(this.virtualPrinter); + List elementAnalyzers = [ fieldDataAnalyzer, - new BarCodeFieldDefaultZplCommandAnalyzer(this._virtualPrinter), - new ChangeAlphanumericDefaultFontZplCommandAnalyzer(this._virtualPrinter), - new Code39BarcodeZplCommandAnalyzer(this._virtualPrinter), - new Code93BarcodeZplCommandAnalyzer(this._virtualPrinter), - new Code128BarcodeZplCommandAnalyzer(this._virtualPrinter), - new CodeEAN13BarcodeZplCommandAnalyzer(this._virtualPrinter), - new CommentZplCommandAnalyzer(this._virtualPrinter), - new DataMatrixZplCommandAnalyzer(this._virtualPrinter), - new DownloadFormatCommandAnalyzer(this._virtualPrinter), - new DownloadGraphicsZplCommandAnalyzer(this._virtualPrinter, this._printerStorage), - new DownloadObjectsZplCommandAnaylzer(this._virtualPrinter, this._printerStorage), - new FieldBlockZplCommandAnalyzer(this._virtualPrinter), - new FieldHexadecimalZplCommandAnalyzer(this._virtualPrinter), - new FieldOrientationZplCommandAnalyzer(this._virtualPrinter), - new FieldNumberCommandAnalyzer(this._virtualPrinter), - new FieldVariableZplCommandAnalyzer(this._virtualPrinter), - new FieldReversePrintZplCommandAnalyzer(this._virtualPrinter), - new LabelReversePrintZplCommandAnalyzer(this._virtualPrinter), - new FieldSeparatorZplCommandAnalyzer(this._virtualPrinter, fieldDataAnalyzer), - new FieldTypesetZplCommandAnalyzer(this._virtualPrinter), - new FieldOriginZplCommandAnalzer(this._virtualPrinter), - new GraphicBoxZplCommandAnalyzer(this._virtualPrinter), - new GraphicCircleZplCommandAnalyzer(this._virtualPrinter), - new GraphicFieldZplCommandAnalyzer(this._virtualPrinter), - new Interleaved2of5BarcodeZplCommandAnalyzer(this._virtualPrinter), - new ImageMoveZplCommandAnalyzer(this._virtualPrinter), - new LabelHomeZplCommandAnalyzer(this._virtualPrinter), - new MaxiCodeBarcodeZplCommandAnalyzer(this._virtualPrinter), - new QrCodeBarcodeZplCommandAnalyzer(this._virtualPrinter), - new PDF417ZplCommandAnalyzer(this._virtualPrinter), - new RecallFormatCommandAnalyzer(this._virtualPrinter), - new RecallGraphicZplCommandAnalyzer(this._virtualPrinter), - new ScalableBitmappedFontZplCommandAnalyzer(this._virtualPrinter), - - }; - - var labelInfos = new List(); - - var elements = new List(); - for (var i = 0; i < zplCommands.Length; i++) + new AztecBarcodeZplCommandAnalyzer(this.virtualPrinter), + new BarCodeFieldDefaultZplCommandAnalyzer(this.virtualPrinter), + new ChangeAlphanumericDefaultFontZplCommandAnalyzer(this.virtualPrinter), + new ChangeInternationalFontCommandAnalyzer(this.virtualPrinter), + new Code39BarcodeZplCommandAnalyzer(this.virtualPrinter), + new Code93BarcodeZplCommandAnalyzer(this.virtualPrinter), + new Code128BarcodeZplCommandAnalyzer(this.virtualPrinter), + new CodeEAN13BarcodeZplCommandAnalyzer(this.virtualPrinter), + new CommentZplCommandAnalyzer(this.virtualPrinter), + new DataMatrixZplCommandAnalyzer(this.virtualPrinter), + new DownloadFormatCommandAnalyzer(this.virtualPrinter), + new DownloadGraphicsZplCommandAnalyzer(this.virtualPrinter, this.printerStorage), + new DownloadObjectsZplCommandAnaylzer(this.virtualPrinter, this.printerStorage), + new FieldBlockZplCommandAnalyzer(this.virtualPrinter), + new FieldHexadecimalZplCommandAnalyzer(this.virtualPrinter), + new FieldOrientationZplCommandAnalyzer(this.virtualPrinter), + new FieldNumberCommandAnalyzer(this.virtualPrinter), + new FieldVariableZplCommandAnalyzer(this.virtualPrinter), + new FieldReversePrintZplCommandAnalyzer(this.virtualPrinter), + new LabelReversePrintZplCommandAnalyzer(this.virtualPrinter), + new FieldSeparatorZplCommandAnalyzer(this.virtualPrinter, fieldDataAnalyzer), + new FieldTypesetZplCommandAnalyzer(this.virtualPrinter), + new FieldOriginZplCommandAnalzer(this.virtualPrinter), + new GraphicBoxZplCommandAnalyzer(this.virtualPrinter), + new GraphicCircleZplCommandAnalyzer(this.virtualPrinter), + new GraphicFieldZplCommandAnalyzer(this.virtualPrinter), + new Interleaved2of5BarcodeZplCommandAnalyzer(this.virtualPrinter), + new ImageMoveZplCommandAnalyzer(this.virtualPrinter), + new LabelHomeZplCommandAnalyzer(this.virtualPrinter), + new MaxiCodeBarcodeZplCommandAnalyzer(this.virtualPrinter), + new QrCodeBarcodeZplCommandAnalyzer(this.virtualPrinter), + new UpcABarcodeZplCommandAnalyzer(this.virtualPrinter), + new UpcEBarcodeZplCommandAnalyzer(this.virtualPrinter), + new UpcExtensionBarcodeZplCommandAnalyzer(this.virtualPrinter), + new PDF417ZplCommandAnalyzer(this.virtualPrinter), + new RecallFormatCommandAnalyzer(this.virtualPrinter), + new RecallGraphicZplCommandAnalyzer(this.virtualPrinter), + new ScalableBitmappedFontZplCommandAnalyzer(this.virtualPrinter), + new AnsiCodabarBarcodeZplCommandAnalyzer(this.virtualPrinter), + ]; + + List labelInfos = []; + + List elements = []; + for (int i = 0; i < zplCommands.Length; i++) { - var currentCommand = zplCommands[i]; + string currentCommand = zplCommands[i]; - if (this._labelStartCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase)) + if (this.labelStartCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase)) { elements.Clear(); - _virtualPrinter.ClearNextDownloadFormatName(); + this.virtualPrinter.ClearNextDownloadFormatName(); continue; } - if (this._labelEndCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase)) + if (this.labelEndCommand.Equals(currentCommand.Trim(), StringComparison.OrdinalIgnoreCase)) { labelInfos.Add(new LabelInfo { - DownloadFormatName = _virtualPrinter.NextDownloadFormatName, + DownloadFormatName = this.virtualPrinter.NextDownloadFormatName, ZplElements = elements.ToArray() }); continue; } - var validAnalyzers = elementAnalyzers.Where(o => o.CanAnalyze(currentCommand)); + IEnumerable validAnalyzers = elementAnalyzers.Where(o => o.CanAnalyze(currentCommand)); if (!validAnalyzers.Any()) { @@ -115,9 +119,9 @@ public AnalyzeInfo Analyze(string zplData) } } - labelInfos = _formatMerger.MergeFormats(labelInfos); + labelInfos = this.formatMerger.MergeFormats(labelInfos); - var analyzeInfo = new AnalyzeInfo + AnalyzeInfo analyzeInfo = new() { LabelInfos = labelInfos.ToArray(), UnknownCommands = unknownCommands.ToArray(), @@ -128,23 +132,22 @@ public AnalyzeInfo Analyze(string zplData) } // When adding new commands: 1 per line, always upper case, comment why if possible - private string[] ignoredCommands = { - "CI", // may be implemented in the future, but for now always set to CI128 + private static readonly HashSet ignoredCommands = new(StringComparer.OrdinalIgnoreCase) + { }; - private string[] SplitZplCommands(string zplData) + private static string[] SplitZplCommands(string zplData) { if (string.IsNullOrWhiteSpace(zplData)) { - return Array.Empty(); + return []; } - var cleanZpl = verticalWhitespaceRegex.Replace(zplData, string.Empty); + string cleanZpl = verticalWhitespaceRegex.Replace(zplData, string.Empty); char caret = '^'; char tilde = '~'; List results = new(200); StringBuilder buffer = new(2000); - HashSet ignoredCommandsHS = new HashSet(ignoredCommands); for (int i = 0; i < cleanZpl.Length; i++) { char c = cleanZpl[i]; @@ -156,19 +159,19 @@ private string[] SplitZplCommands(string zplData) // all commands have at least 3 chars, even ^A because of required font parameter if (command.Length > 2) { - PatchCommand(ref command, ref caret, ref tilde); + PatchCommand(ref command, caret, tilde); - var commandLetters = command.Substring(1, 2).ToUpper(); + string commandLetters = command.Substring(1, 2).ToUpper(); if (commandLetters == "CT") { - tilde = command[3]; + tilde = command.Length > 3 ? command[3] : c; } else if (commandLetters == "CC") { - caret = command[3]; + caret = command.Length > 3 ? command[3] : c; } - else if (!ignoredCommandsHS.Contains(commandLetters)) + else if (!ignoredCommands.Contains(commandLetters)) { results.Add(command); } @@ -180,26 +183,30 @@ private string[] SplitZplCommands(string zplData) } // no else case, multiple ^ or ~ in a row should not be valid commands to be processed } + buffer.Append(c); } + string lastCommand = buffer.ToString(); if (lastCommand.Length > 0) { - PatchCommand(ref lastCommand, ref caret, ref tilde); + PatchCommand(ref lastCommand, caret, tilde); results.Add(lastCommand); } + return results.ToArray(); } - private void PatchCommand(ref string command, ref char caret, ref char tilde) + private static void PatchCommand(ref string command, char caret, char tilde) { if (caret != '^' && command[0] == caret) { - command = '^' + command.Remove(0, 1); + command = '^' + command.Substring(1); } + if (tilde != '~' && command[0] == tilde) { - command = '~' + command.Remove(0, 1); + command = '~' + command.Substring(1); } } } diff --git a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs index a94c33b8..e60b17f5 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs @@ -1,6 +1,10 @@ +using BinaryKits.Zpl.Label; using BinaryKits.Zpl.Label.Elements; using BinaryKits.Zpl.Viewer.ElementDrawers; +using BinaryKits.Zpl.Viewer.Helpers; + using SkiaSharp; + using System; using System.Collections.Generic; using System.IO; @@ -10,37 +14,41 @@ namespace BinaryKits.Zpl.Viewer { public class ZplElementDrawer { - private readonly DrawerOptions _drawerOptions; - private readonly IPrinterStorage _printerStorage; - private readonly IElementDrawer[] _elementDrawers; + private static readonly int pdfDpi = 72; + private static readonly float zplDpi = 203.2f; + private static readonly float pdfScaleFactor = pdfDpi / zplDpi; + + private readonly DrawerOptions drawerOptions; + private readonly IPrinterStorage printerStorage; + private readonly IElementDrawer[] elementDrawers; public ZplElementDrawer(IPrinterStorage printerStorage, DrawerOptions drawerOptions = null) { - if (drawerOptions == null) - { - drawerOptions = new DrawerOptions(); - } - this._drawerOptions = drawerOptions; - this._printerStorage = printerStorage; - this._elementDrawers = new IElementDrawer[] - { + this.drawerOptions = drawerOptions ?? new DrawerOptions(); + this.printerStorage = printerStorage; + this.elementDrawers = [ + new AztecBarcodeElementDrawer(), new Barcode128ElementDrawer(), new Barcode39ElementDrawer(), new Barcode93ElementDrawer(), new BarcodeEAN13ElementDrawer(), + new BarcodeUpcAElementDrawer(), + new BarcodeUpcEElementDrawer(), + new BarcodeUpcExtensionElementDrawer(), new DataMatrixElementDrawer(), new FieldBlockElementDrawer(), new GraphicBoxElementDrawer(), new GraphicCircleElementDrawer(), new GraphicFieldElementDrawer(), - new Interleaved2of5BarcodeDrawer(), new ImageMoveElementDrawer(), + new Interleaved2of5BarcodeDrawer(), new MaxiCodeElementDrawer(), - new QrCodeElementDrawer(), new Pdf417ElementDrawer(), + new QrCodeElementDrawer(), new RecallGraphicElementDrawer(), - new TextFieldElementDrawer() - }; + new TextFieldElementDrawer(), + new BarcodeAnsiCodabarElementDrawer(), + ]; } /// @@ -91,36 +99,50 @@ public List DrawMulti( double labelHeight = 152.4, int printDensityDpmm = 8) { - var result = new List(); - var imageHistory = new List(); - var labelImageWidth = Convert.ToInt32(labelWidth * printDensityDpmm); - var labelImageHeight = Convert.ToInt32(labelHeight * printDensityDpmm); + List result = []; + List imageHistory = []; + int labelImageWidth = Convert.ToInt32(labelWidth * printDensityDpmm); + int labelImageHeight = Convert.ToInt32(labelHeight * printDensityDpmm); //use SKNWayCanvas to be able to draw on multiple canvases - using var skCanvas = new SKNWayCanvas(labelImageWidth, labelImageHeight); + using SKNWayCanvas skCanvas = new(labelImageWidth, labelImageHeight); //add Bitmap canvas - var info = new SKImageInfo(labelImageWidth, labelImageHeight); - var surface = SKSurface.Create(info); - using var skImageCanvas = surface.Canvas; + SKImageInfo info = new(labelImageWidth, labelImageHeight); + SKSurface surface = SKSurface.Create(info); + using SKCanvas skImageCanvas = surface.Canvas; skCanvas.AddCanvas(skImageCanvas); //add PDF canvas // - When drawing PDF we need the Bitmap as well to fix inverted coloring Stream pdfStream = new MemoryStream(); - using var document = SKDocument.CreatePdf(pdfStream); - using var pdfCanvas = document.BeginPage(labelImageWidth, labelImageHeight); - if (this._drawerOptions.PdfOutput == true) + using SKDocument document = SKDocument.CreatePdf(pdfStream); + + using SKCanvas pdfCanvas = document.BeginPage( + (float)(UnitsHelper.ConvertMillimetersToInches(labelWidth) * pdfDpi), + (float)(UnitsHelper.ConvertMillimetersToInches(labelHeight) * pdfDpi)); + + pdfCanvas.Scale(pdfScaleFactor, pdfScaleFactor); + + if (this.drawerOptions.PdfOutput == true) { skCanvas.AddCanvas(pdfCanvas); } //make sure to have a transparent canvas for SKBlendMode.Xor to work properly skCanvas.Clear(SKColors.Transparent); + InternationalFont internationalFont = InternationalFont.ZCP850; + SKPoint currentDefaultPosition = SKPoint.Empty; - foreach (var element in elements) + foreach (ZplElementBase element in elements) { - var drawer = this._elementDrawers.SingleOrDefault(o => o.CanDraw(element)); + if (element is ZplChangeInternationalFont changeFont) + { + internationalFont = changeFont.InternationalFont; + continue; + } + + IElementDrawer drawer = this.elementDrawers.SingleOrDefault(o => o.CanDraw(element)); if (drawer == null) { continue; @@ -139,7 +161,7 @@ public List DrawMulti( && !drawer.ForceBitmapDraw(element)) { //save state before inverted draw - if (this._drawerOptions.PdfOutput == true) + if (this.drawerOptions.PdfOutput == true) { imageHistory.Add(surface.Snapshot()); } @@ -147,15 +169,15 @@ public List DrawMulti( else if (drawer.IsReverseDraw(element)) { //basically only ZplGraphicBox/Circle depending on requirements - using var skBitmapInvert = new SKBitmap(labelImageWidth, labelImageHeight); - using var skCanvasInvert = new SKCanvas(skBitmapInvert); + using SKBitmap skBitmapInvert = new(labelImageWidth, labelImageHeight); + using SKCanvas skCanvasInvert = new(skBitmapInvert); skCanvasInvert.Clear(SKColors.Transparent); - drawer.Prepare(this._printerStorage, skCanvasInvert); - drawer.Draw(element, _drawerOptions); + drawer.Prepare(this.printerStorage, skCanvasInvert); + currentDefaultPosition = drawer.Draw(element, this.drawerOptions, currentDefaultPosition, internationalFont, printDensityDpmm); //save state before inverted draw - if (this._drawerOptions.PdfOutput == true) + if (this.drawerOptions.PdfOutput == true) { imageHistory.Add(surface.Snapshot()); } @@ -163,27 +185,31 @@ public List DrawMulti( //use color inversion on an reverse draw white element if (drawer.IsWhiteDraw(element)) { - this.InvertDrawWhite(skCanvas, skBitmapInvert); + InvertDrawWhite(skCanvas, skBitmapInvert); } else { - this.InvertDraw(skCanvas, skBitmapInvert); + InvertDraw(skCanvas, skBitmapInvert); } continue; } - drawer.Prepare(this._printerStorage, skCanvas); - drawer.Draw(element, _drawerOptions); + drawer.Prepare(this.printerStorage, skCanvas); + currentDefaultPosition = drawer.Draw(element, this.drawerOptions, currentDefaultPosition, internationalFont, printDensityDpmm); continue; } catch (Exception ex) { if (element is ZplBarcode barcodeElement) + { throw new Exception($"Error on zpl element \"{barcodeElement.Content}\": {ex.Message}", ex); + } else if (element is ZplDataMatrix dataMatrixElement) + { throw new Exception($"Error on zpl element \"{dataMatrixElement.Content}\": {ex.Message}", ex); + } else { throw; @@ -192,33 +218,35 @@ public List DrawMulti( } //check if we need to set a white background - var image = surface.Snapshot(); - if (this._drawerOptions.OpaqueBackground == true) + SKImage image = surface.Snapshot(); + if (this.drawerOptions.OpaqueBackground == true) { - using var surfaceWhiteBg = SKSurface.Create(info); - using var skImageCanvasWhiteBg = surfaceWhiteBg.Canvas; + using SKSurface surfaceWhiteBg = SKSurface.Create(info); + using SKCanvas skImageCanvasWhiteBg = surfaceWhiteBg.Canvas; skImageCanvasWhiteBg.Clear(SKColors.White); - var surfaceImage = surface.Snapshot(); - var paint = new SKPaint(); - paint.BlendMode = SKBlendMode.SrcOver; + SKImage surfaceImage = surface.Snapshot(); + SKPaint paint = new() + { + BlendMode = SKBlendMode.SrcOver + }; skImageCanvasWhiteBg.DrawImage(surfaceImage, 0f, 0f, paint); image = surfaceWhiteBg.Snapshot(); } - var imageData = image.Encode(_drawerOptions.RenderFormat, _drawerOptions.RenderQuality); + SKData imageData = image.Encode(this.drawerOptions.RenderFormat, this.drawerOptions.RenderQuality); result.Add(imageData.ToArray()); //only return image - if (this._drawerOptions.PdfOutput == false) + if (this.drawerOptions.PdfOutput == false) { result.Add(null); return result; } //Fix the PDF blend - this.FixPdfInvertDraw(info, imageHistory, surface, skCanvas); + FixPdfInvertDraw(info, imageHistory, surface, skCanvas); //close the PDF document document.EndPage(); @@ -237,67 +265,159 @@ public List DrawMulti( return result; } + /// + /// Draw the label on the provided surface + /// + /// Skia Surface + /// Zpl elements + /// Label width in millimeter + /// Label height in millimeter + /// Dots per millimeter + /// + public void DrawSurface(SKSurface surface, + ZplElementBase[] elements, + double labelWidth = 101.6, + double labelHeight = 152.4, + int printDensityDpmm = 8) + { + List result = []; + List imageHistory = []; + int labelImageWidth = Convert.ToInt32(labelWidth * printDensityDpmm); + int labelImageHeight = Convert.ToInt32(labelHeight * printDensityDpmm); + + SKCanvas skCanvas = surface.Canvas; + //This has an issue with AvaloniaUI making the window transparent. + skCanvas.Clear(SKColors.Transparent); + InternationalFont internationalFont = InternationalFont.ZCP850; + SKPoint currentDefaultPosition = SKPoint.Empty; + + foreach (ZplElementBase element in elements) + { + if (element is ZplChangeInternationalFont changeFont) + { + internationalFont = changeFont.InternationalFont; + continue; + } + + IElementDrawer drawer = this.elementDrawers.SingleOrDefault(o => o.CanDraw(element)); + if (drawer == null) + { + continue; + } + + try + { + if (drawer.IsReverseDraw(element)) + { + //basically only ZplGraphicBox/Circle depending on requirements + using SKBitmap skBitmapInvert = new(labelImageWidth, labelImageHeight); + using SKCanvas skCanvasInvert = new(skBitmapInvert); + skCanvasInvert.Clear(SKColors.Transparent); + + drawer.Prepare(this.printerStorage, skCanvasInvert); + currentDefaultPosition = drawer.Draw(element, this.drawerOptions, currentDefaultPosition, internationalFont, printDensityDpmm); + + //use color inversion on an reverse draw white element + if (drawer.IsWhiteDraw(element)) + { + InvertDrawWhite(skCanvas, skBitmapInvert); + } + else + { + InvertDraw(skCanvas, skBitmapInvert); + } + + continue; + } + + drawer.Prepare(this.printerStorage, skCanvas); + currentDefaultPosition = drawer.Draw(element, this.drawerOptions, currentDefaultPosition, internationalFont, printDensityDpmm); + + continue; + } + catch (Exception ex) + { + if (element is ZplBarcode barcodeElement) + { + throw new Exception($"Error on zpl element \"{barcodeElement.Content}\": {ex.Message}", ex); + } + else if (element is ZplDataMatrix dataMatrixElement) + { + throw new Exception($"Error on zpl element \"{dataMatrixElement.Content}\": {ex.Message}", ex); + } + else + { + throw; + } + } + } + } + /** * PDF transparency and SKBlendMode are not very good friends, SKBlendMode.Xor behaves as SKBlendMode.SrcOver. * * This function extracts all the pixels that are removed in the draw process * Then that is used to make a white image as overlay in the PDF to get the same effect as SKBlendMode.Xor */ - private void FixPdfInvertDraw(SKImageInfo info, List imageHistory, SKSurface surface, SKCanvas skCanvas) + private static void FixPdfInvertDraw(SKImageInfo info, List imageHistory, SKSurface surface, SKCanvas skCanvas) { //fix inverted colors - using var surfacePdfInvertColorFix = SKSurface.Create(info); - using var skImageCanvasPdfInvertColorFix = surfacePdfInvertColorFix.Canvas; + using SKSurface surfacePdfInvertColorFix = SKSurface.Create(info); + using SKCanvas skImageCanvasPdfInvertColorFix = surfacePdfInvertColorFix.Canvas; skImageCanvasPdfInvertColorFix.Clear(SKColors.Transparent); //make an image of everything that was once colored - foreach (var imageHistoryState in imageHistory) + foreach (SKImage imageHistoryState in imageHistory) { - var pdfPaint = new SKPaint(); - pdfPaint.BlendMode = SKBlendMode.SrcOver; + SKPaint pdfPaint = new() + { + BlendMode = SKBlendMode.SrcOver + }; skImageCanvasPdfInvertColorFix.DrawImage(imageHistoryState, 0f, 0f, pdfPaint); } //subtract the parts that are transparent in the final image - var finalSurfaceImage = surface.Snapshot(); - var pdfFinalPaint = new SKPaint(); - pdfFinalPaint.BlendMode = SKBlendMode.DstOut; + SKImage finalSurfaceImage = surface.Snapshot(); + SKPaint pdfFinalPaint = new() + { + BlendMode = SKBlendMode.DstOut + }; skImageCanvasPdfInvertColorFix.DrawImage(finalSurfaceImage, 0f, 0f, pdfFinalPaint); //now invert the colors of the pixels that should be white place it on the canvas - var pdfTransparentPartsImage = surfacePdfInvertColorFix.Snapshot(); - var pdfTransparentPartsBitmap = SKBitmap.FromImage(pdfTransparentPartsImage); - var pdfFinalPaintInverted = new SKPaint(); - var inverter = new float[20] { + SKImage pdfTransparentPartsImage = surfacePdfInvertColorFix.Snapshot(); + SKBitmap pdfTransparentPartsBitmap = SKBitmap.FromImage(pdfTransparentPartsImage); + SKPaint pdfFinalPaintInverted = new(); + float[] inverter = [ -1f, 0f, 0f, 0f, 1f, 0f, -1f, 0f, 0f, 1f, 0f, 0f, -1f, 0f, 1f, 0f, 0f, 0f, 1f, 0f - }; + ]; pdfFinalPaintInverted.ColorFilter = SKColorFilter.CreateColorMatrix(inverter); pdfFinalPaintInverted.BlendMode = SKBlendMode.SrcOver; skCanvas.DrawBitmap(pdfTransparentPartsBitmap, 0, 0, pdfFinalPaintInverted); } - private void InvertDraw(SKCanvas baseCanvas, SKBitmap bmToInvert) + private static void InvertDraw(SKCanvas baseCanvas, SKBitmap bmToInvert) { - using (SKPaint paint = new SKPaint()) + using (SKPaint paint = new()) { paint.BlendMode = SKBlendMode.Xor; baseCanvas.DrawBitmap(bmToInvert, 0, 0, paint); } } - private void InvertDrawWhite(SKCanvas baseCanvas, SKBitmap bmToInvert) + private static void InvertDrawWhite(SKCanvas baseCanvas, SKBitmap bmToInvert) { - using (SKPaint paint = new SKPaint()) + using (SKPaint paint = new()) { - var inverter = new float[20] { + float[] inverter = [ -1f, 0f, 0f, 0f, 1f, 0f, -1f, 0f, 0f, 1f, 0f, 0f, -1f, 0f, 1f, 0f, 0f, 0f, 1f, 0f - }; + ]; paint.ColorFilter = SKColorFilter.CreateColorMatrix(inverter); paint.BlendMode = SKBlendMode.Xor; baseCanvas.DrawBitmap(bmToInvert, 0, 0, paint);