From 70cebebb3f64d1d1eeb1336033f714db5cd7a62b Mon Sep 17 00:00:00 2001 From: Yiping Date: Tue, 19 Sep 2023 10:52:14 +0800 Subject: [PATCH 1/7] Create dotnet - test.yml --- .github/workflows/dotnet - test.yml | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/dotnet - test.yml diff --git a/.github/workflows/dotnet - test.yml b/.github/workflows/dotnet - test.yml new file mode 100644 index 00000000..b6101dda --- /dev/null +++ b/.github/workflows/dotnet - test.yml @@ -0,0 +1,50 @@ +name: .NET + +on: + push: + branches: [ develop ] + pull_request: + branches: [ develop ] + +jobs: + build-windows: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET 6.0 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + working-directory: ./src + run: dotnet restore + - name: Build + working-directory: ./src + run: dotnet build --configuration Release --no-restore /p:NoWarn=1591 + - name: Test + working-directory: ./src + run: dotnet test --configuration Release --no-restore --no-build --verbosity normal + + build-linux: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET 6.0 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + working-directory: ./src + run: dotnet restore + - name: Build + working-directory: ./src + run: dotnet build --configuration Release --no-restore /p:NoWarn=1591 + - name: Test + working-directory: ./src + run: dotnet test --configuration Release --no-restore --no-build --verbosity normal + + From eaa2a0881e57bc8371aaaeb26974d259d0680403 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:31:04 +0000 Subject: [PATCH 2/7] Bump SkiaSharp from 2.88.3 to 2.88.6 in /src/BinaryKits.Zpl.Viewer Bumps [SkiaSharp](https://github.com/mono/SkiaSharp) from 2.88.3 to 2.88.6. - [Release notes](https://github.com/mono/SkiaSharp/releases) - [Commits](https://github.com/mono/SkiaSharp/compare/v2.88.3...v2.88.6) --- updated-dependencies: - dependency-name: SkiaSharp dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj b/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj index a4fd9e5f..4debec17 100644 --- a/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj +++ b/src/BinaryKits.Zpl.Viewer/BinaryKits.Zpl.Viewer.csproj @@ -1,4 +1,4 @@ - + net472;netstandard2.0;net6.0 @@ -23,7 +23,7 @@ - + From ddc7cb750fa089b4af7e6c42c2ba34554d632de9 Mon Sep 17 00:00:00 2001 From: Dmitrii Savchenkov Date: Thu, 18 Jan 2024 06:19:43 +0100 Subject: [PATCH 3/7] fix(viewer): cannot find package vue@next (#208) * fix(viewer): cannot find package vue@next * Update index.html Don't use specific versions for web dependencies. --- src/BinaryKits.Zpl.Viewer.WebApi/wwwroot/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/wwwroot/index.html b/src/BinaryKits.Zpl.Viewer.WebApi/wwwroot/index.html index 0c643c7a..4d89255a 100644 --- a/src/BinaryKits.Zpl.Viewer.WebApi/wwwroot/index.html +++ b/src/BinaryKits.Zpl.Viewer.WebApi/wwwroot/index.html @@ -3,9 +3,9 @@ BinaryKits.Zpl.Viewer.WebApi - - - + + +
@@ -209,4 +209,4 @@

Label rendering error

Vue.createApp(App).mount('#app'); - \ No newline at end of file + From 552973b51e226048ee666d403d6e0c18a7b74c02 Mon Sep 17 00:00:00 2001 From: reportingissue <136993729+reportingissue@users.noreply.github.com> Date: Thu, 18 Jan 2024 00:31:09 -0500 Subject: [PATCH 4/7] Enable ^FV command (needed for UPS) (#195) * Enable ^FV command - Based off ^FD --- .../FieldDataZplCommandAnalyzer.cs | 2 +- .../FieldVarialbleZplCommandAnalyzer.cs | 14 ++++++++++++++ src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs index 84a3faf8..0121a75f 100644 --- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs @@ -16,7 +16,7 @@ public class FieldDataZplCommandAnalyzer : ZplCommandAnalyzerBase 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); - public FieldDataZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^FD", virtualPrinter) { } + public FieldDataZplCommandAnalyzer(VirtualPrinter virtualPrinter, string prefix="^FD") : base(prefix, virtualPrinter) { } /// public override ZplElementBase Analyze(string zplCommand) diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs new file mode 100644 index 00000000..581a6509 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldVarialbleZplCommandAnalyzer.cs @@ -0,0 +1,14 @@ +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 + // 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 + // using FDs as static elements of template and FVs as variable parts. + // Subsequent labels only require FV to draw the variable parts. + public class FieldVariableZplCommandAnalyzer : FieldDataZplCommandAnalyzer + { + public FieldVariableZplCommandAnalyzer(VirtualPrinter virtualPrinter): base(virtualPrinter, "^FV") { } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs index 3fe6aa15..6083209b 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs @@ -48,6 +48,7 @@ public AnalyzeInfo Analyze(string zplData) new FieldBlockZplCommandAnalyzer(this._virtualPrinter), new FieldHexadecimalZplCommandAnalyzer(this._virtualPrinter), new FieldNumberCommandAnalyzer(this._virtualPrinter), + new FieldVariableZplCommandAnalyzer(this._virtualPrinter), new FieldReversePrintZplCommandAnalyzer(this._virtualPrinter), new LabelReversePrintZplCommandAnalyzer(this._virtualPrinter), new FieldSeparatorZplCommandAnalyzer(this._virtualPrinter, fieldDataAnalyzer), From 197c4446b6027131d9ca74c2106439ea8267ade3 Mon Sep 17 00:00:00 2001 From: reportingissue <136993729+reportingissue@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:35:11 -0400 Subject: [PATCH 5/7] ZPL Parser: Enable ignoring certain commands (#194) * Enable ignoring certain commands - small refactors + comments in the zpl parser * Comment specification --- src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs index 6083209b..7470fe48 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs @@ -122,6 +122,11 @@ public AnalyzeInfo Analyze(string zplData) return analyzeInfo; } + // 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 string[] SplitZplCommands(string zplData) { if (string.IsNullOrWhiteSpace(zplData)) @@ -134,6 +139,7 @@ private string[] SplitZplCommands(string zplData) 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]; @@ -141,25 +147,33 @@ private string[] SplitZplCommands(string zplData) { string command = buffer.ToString(); buffer.Clear(); + + // 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); - results.Add(command); - if (command.Substring(1, 2) == "CT") + + var commandLetters = command.Substring(1, 2).ToUpper(); + + if (ignoredCommandsHS.Contains(commandLetters)) { + continue; + } + else if (commandLetters == "CT") { tilde = command[3]; - results.RemoveAt(results.Count - 1); } - else if (command.Substring(1, 2) == "CC") + else if (commandLetters == "CC") { caret = command[3]; - results.RemoveAt(results.Count - 1); + } else { + results.Add(command); } } // likely invalid command else if (command.Trim().Length > 0) { results.Add(command.Trim()); } + // no else case, multiple ^ or ~ in a row should not be valid commands to be processed } buffer.Append(c); } From 06a30311fbf6f346ed28bd41e99a9b050595957a Mon Sep 17 00:00:00 2001 From: reportingissue <136993729+reportingissue@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:36:30 -0400 Subject: [PATCH 6/7] Add documentation on how to add barcode support (#198) --- src/BinaryKits.Zpl.Viewer/README.md | 83 ++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/BinaryKits.Zpl.Viewer/README.md b/src/BinaryKits.Zpl.Viewer/README.md index 767d2338..9d72a1be 100644 --- a/src/BinaryKits.Zpl.Viewer/README.md +++ b/src/BinaryKits.Zpl.Viewer/README.md @@ -21,4 +21,85 @@ foreach (var labelInfo in analyzeInfo.LabelInfos) var imageData = drawer.Draw(labelInfo.ZplElements); //imageData is bytes of png image } -``` \ No newline at end of file +``` + +# 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) +- [PDF417 Barcode](https://github.com/BinaryKits/BinaryKits.Zpl/pull/190/files) + +## Steps +Generally, looking at files in the directory for each step should give you a clue on how to implement a file. + +### 1: Create the abstract element +This is a class used to represent the barcode with all it's settings, mostly to be used for zpl generation. +We are currently in the middle of a (stalled) refactor which leads to some amount of code duplication. +A class should be created in these `/`: +- `BinaryKits.Zpl.Label/Elements/` +- `BinaryKits.Zpl.Protocol/Commands/` + +For 2d barcodes, implement `ZplPositionedElementBase` and `IFormatElement`, for 1d barcodes, subclass `ZplBarcode` + +### 2: Create a model in `BinaryKits.Zpl.Viewer/Models/` +This one is only used for the viewer project and should contain mostly the same properties as the class created in the previous step. + +### 3: Create the command analyzer in `BinaryKits.Zpl.Viewer/CommandAnalyzers/` +This is where you write the code for parsing zpl to the Model/Element. + +- Subclass from `ZplCommandAnalyzerBase` +- Use `this.SplitCommand` get all the zpl arguments +- Remember to check that the length of args array is long enough before trying to parse at an index +- Remember to set the defaults each parameter before parsing + - There are parameters stored in the virtual printer such as `^BY` + - Otherwise use the defaults as described in the zpl programming manual +- Because there is always data to encode, set the next field data encountered by the virtual printer to return the content to the model + +### 4: Add an entry to `BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs` +This is to make sure that we grab the `text`, the model from the previous step it into a new instance of the abstract element. + +Find the massive `if` chain following `if (this.VirtualPrinter.NextElementFieldData != null)` and add an entry for your mode. + +Architecturally, this type of hard binding is probably not good. We should probably fix this. + +### 5: Add an entry to `BinaryKits.Zpl.Viewer/ZPLAnalyzer.cs` +Find the List `elementAnalyzers` and instantiate your analyzer there. + +### 6: Create a drawer in `BinaryKits.Zpl.Viewer/ElementDrawers` +- Subclass `BarcodeDrawerBase` +- Implement `CanDraw` by checking against the abstract element in step 1. +- Implement `Draw`. Working from the end: + - The end goal is to write some pixels (a skia bitmap) to the base canvas with `this.DrawBarcode` + - Those pixels will be obtained by converting an abstract barcode drawing to a png `SKBitmap` + - The abstract drawing will be generated by calling an external library with the correct parameters obtained from the abstract element + - Zxing.net uses hints to pass in extra parameters + - Some adaptative helper functions may needed to convert between the library types and skia bitmaps or binarykit.zpl models + - `BarcodeDrawerBase` may have some helper functions needed + +### 7: Add an entry to `BinaryKits.Zpl.Viewer/ZPLElementDrawer.cs` +Find the array `this._elementDrawers` and instantiate your drawer there. + +### 8: Create a test in to `BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs` +- todo: load data from BinaryKits.Zpl.Viewer.UnitTest/Data/zpl like in the webapi project +- Use the `DefaultPrint` function when possible, you can pass dimensions, density and drawer options +- todo: an empty custom file `BinaryKits.Zpl.Viewer.UnitTest/Data/zpl/custom.zpl2` is not under vcs to enable quick testing From a41fc1867fdbd1e3f1f4f5cdd9bfa8601c38c5de Mon Sep 17 00:00:00 2001 From: reportingissue <136993729+reportingissue@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:38:47 -0400 Subject: [PATCH 7/7] Change invertdraw to skia xor blending (#193) - Also added tests - Refactored viewer tests --- .../DrawerTest.cs | 108 +++++++++++++++--- src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs | 35 +----- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs b/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs index 26b52851..c21a637b 100644 --- a/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs +++ b/src/BinaryKits.Zpl.Viewer.UnitTest/DrawerTest.cs @@ -4,8 +4,7 @@ using System; using System.Collections.Generic; using System.IO; -using ZXing; -using ZXing.Datamatrix; + namespace BinaryKits.Zpl.Viewer.UnitTest { @@ -40,17 +39,7 @@ public void FontAssignment() return SKTypeface.Default; } }; - IPrinterStorage printerStorage = new PrinterStorage(); - var drawer = new ZplElementDrawer(printerStorage, drawOptions); - - var analyzer = new ZplAnalyzer(printerStorage); - var analyzeInfo = analyzer.Analyze(zplString); - - foreach (var labelInfo in analyzeInfo.LabelInfos) - { - var imageData = drawer.Draw(labelInfo.ZplElements, 300, 300, 8); - File.WriteAllBytes("test.png", imageData); - } + DefaultPrint(zplString, "font-assign.png", 300, 300, 8, drawOptions); } [TestMethod] @@ -79,16 +68,101 @@ public void FormatHandling() ^PQ1,0,1,N ^XZ ^FX"; + DefaultPrint(zplString, "merge-test.png", 100, 100, 8); + } + [TestMethod] + public void InvertColor() + { + // Example in ZPL manual + string test1 = @" +^XA +^FO10,100 +^GB70,70,70,,3^FS +^FO110,100 +^GB70,70,70,,3^FS +^FO210,100 +^GB70,70,70,,3^FS +^FO310,100 +^GB70,70,70,,3^FS +^FO17,110 +^CF0,70,93 +^FR +^FDREVERSE^FS +^XZ +"; + // from https://github.com/BinaryKits/BinaryKits.Zpl/pull/64 + string test2 = @" +^XA +^FR +^FO50,50 +^GB100,100,10,W,5^FS +^FR +^FO200,50 +^GB100,100,10,W,5^FS +^FO100,120 +^GB30,25,10,B,2^FS +^FO250,120 +^GB30,25,10,B,2^FS +^FO130,180 +^GB90,90,45,B,8^FS +^FR +^FO75,300 +^GB30,20,10,W,0^FS +^FR +^FO265,300 +^GB30,20,10,W,0^FS +^FR +^FO105,320 +^GB160,20,10,W,0^FS +^FR +^FO120,310 +^GB10,20,5,B,0^FS +^FR +^FO140,310 +^GB10,20,5,B,0^FS +^FR +^FO160,310 +^GB10,20,5,B,0^FS +^FR +^FO180,310 +^GB10,20,5,B,0^FS +^FR +^FO200,310 +^GB10,20,5,B,0^FS +^FR +^FO220,310 +^GB10,20,5,B,0^FS +^FR +^FO240,310 +^GB10,20,5,B,0^FS +^FO150,330 +^GB70,90,45,B,0^FS +^XZ +"; + DefaultPrint(test1, "inverted1.png", 100, 100, 8); + DefaultPrint(test2, "inverted2.png"); + } + + /// + /// Generic printer to test zpl -> png output + /// + /// + /// PNG filename ex: "file.png" + /// + /// + /// + /// + private void DefaultPrint(string zpl, string outputFilename, double width=101.6, double height=152.4, int ppmm=8, DrawerOptions options=null) { IPrinterStorage printerStorage = new PrinterStorage(); - var drawer = new ZplElementDrawer(printerStorage); + var drawer = new ZplElementDrawer(printerStorage, options); var analyzer = new ZplAnalyzer(printerStorage); - var analyzeInfo = analyzer.Analyze(zplString); + var analyzeInfo = analyzer.Analyze(zpl); foreach (var labelInfo in analyzeInfo.LabelInfos) { - var imageData = drawer.Draw(labelInfo.ZplElements, 300, 300, 8); - File.WriteAllBytes("merge-test.png", imageData); + var imageData = drawer.Draw(labelInfo.ZplElements, width, height, ppmm); + File.WriteAllBytes(outputFilename, imageData); } } } diff --git a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs index 72bf4c23..35bd13de 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs @@ -79,7 +79,7 @@ public byte[] Draw( drawer.Draw(element, _drawerOptions); - this.InvertDraw(skBitmap, skBitmapInvert); + this.InvertDraw(skCanvas, skBitmapInvert); continue; } @@ -124,37 +124,12 @@ public byte[] Draw( return data.ToArray(); } - private void InvertDraw(SKBitmap skBitmap, SKBitmap skBitmapInvert) + private void InvertDraw(SKCanvas baseCanvas, SKBitmap bmToInvert) { - // Fast local copy - var originalBytes = skBitmap.GetPixelSpan(); - var invertBytes = skBitmapInvert.GetPixelSpan(); - - int total = originalBytes.Length / 4; - for (int i = 0; i < total; i++) + using (SKPaint paint = new SKPaint()) { - // RGBA8888 - int rLoc = (i << 2); - int gLoc = (i << 2) + 1; - int bLoc = (i << 2) + 2; - int aLoc = (i << 2) + 3; - if (invertBytes[aLoc] == 0) - { - continue; - } - - // Set color - byte rByte = (byte)(originalBytes[rLoc] ^ invertBytes[rLoc]); - byte gByte = (byte)(originalBytes[gLoc] ^ invertBytes[gLoc]); - byte bByte = (byte)(originalBytes[bLoc] ^ invertBytes[bLoc]); - byte aByte = (byte)(originalBytes[aLoc] ^ invertBytes[aLoc]); - - var targetColor = new SKColor(rByte, gByte, bByte, aByte); - - int x, y; - y = Math.DivRem(i, skBitmapInvert.Width, out x); - - skBitmap.SetPixel(x, y, targetColor); + paint.BlendMode = SKBlendMode.Xor; + baseCanvas.DrawBitmap(bmToInvert, 0, 0, paint); } } }