From b28eef4f5af7c6c95238f827c9f071fa39c01908 Mon Sep 17 00:00:00 2001 From: "marius.starke" Date: Tue, 23 Apr 2024 09:49:52 +0200 Subject: [PATCH 1/2] Added: Barcode93 support --- .../BarcodeTest.cs | 16 +++++ .../Elements/ZplBarcode93.cs | 70 +++++++++++++++++++ src/BinaryKits.Zpl.TestConsole/Program.cs | 11 +-- .../Code93BarcodeZplCommandAnalyzer.cs | 55 +++++++++++++++ .../FieldDataZplCommandAnalyzer.cs | 8 ++- .../ElementDrawers/Barcode93ElementDrawer.cs | 57 +++++++++++++++ .../Models/Code93BarcodeFieldData.cs | 13 ++++ src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs | 11 ++- src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs | 29 ++++---- 9 files changed, 246 insertions(+), 24 deletions(-) create mode 100644 src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs create mode 100644 src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs create mode 100644 src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs create mode 100644 src/BinaryKits.Zpl.Viewer/Models/Code93BarcodeFieldData.cs diff --git a/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs b/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs index ff080acd..f6a33f9b 100644 --- a/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs +++ b/src/BinaryKits.Zpl.Label.UnitTest/BarcodeTest.cs @@ -24,6 +24,22 @@ public void Barcode39() 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); } + [TestMethod] + public void Barcode93() + { + var elements = new List + { + new ZplBarcode93("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^CI28\n\n^FO100,300\n^BY2,3\n^BAN,100,Y,N,N\n^FD123ABC^FS\n^XZ", output); + } + [TestMethod] public void Barcode128() { diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs new file mode 100644 index 00000000..ed5a1b4a --- /dev/null +++ b/src/BinaryKits.Zpl.Label/Elements/ZplBarcode93.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; + +namespace BinaryKits.Zpl.Label.Elements +{ + /// + /// Code 93 Barcode + /// + public class ZplBarcode93 : ZplBarcode + { + public bool CheckDigit { get; private set; } + + /// + /// Code 93 Barcode + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public ZplBarcode93( + string content, + int positionX, + int positionY, + int height = 100, + int moduleWidth = 2, + double wideBarToNarrowBarWidthRatio = 3, + FieldOrientation fieldOrientation = FieldOrientation.Normal, + bool printInterpretationLine = true, + bool printInterpretationLineAboveCode = false, + bool checkDigit = false, + bool bottomToTop = false) + : base(content, + positionX, + positionY, + height, + moduleWidth, + wideBarToNarrowBarWidthRatio, + fieldOrientation, + printInterpretationLine, + printInterpretationLineAboveCode, + bottomToTop) + { + this.CheckDigit = checkDigit; + } + + /// + public override IEnumerable Render(ZplRenderOptions context) + { + //TODO:Add 'mode' + + //^FO100,100 ^ BY3 + //^BAN,100,Y,N,N + //^FD123456 ^ FS + 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"); + + return result; + } + } +} diff --git a/src/BinaryKits.Zpl.TestConsole/Program.cs b/src/BinaryKits.Zpl.TestConsole/Program.cs index 7c68faa2..e74a9429 100644 --- a/src/BinaryKits.Zpl.TestConsole/Program.cs +++ b/src/BinaryKits.Zpl.TestConsole/Program.cs @@ -84,10 +84,11 @@ static string RenderLabel3() { new ZplBarcode128("Barcode128", 10, 0), new ZplBarcode39("Barcode39", 10, 150), - new ZplBarcodeAnsiCodabar("123456", 'a', 'd', 10, 300, 100), - new ZplBarcodeEan13("123456789", 10, 450), - new ZplBarcodeInterleaved2of5("123456789", 10, 600), - new ZplQrCode("BinaryKits ZplUtility BinaryKits ZplUtility BinaryKits ZplUtility", 10, 800, magnificationFactor: 6) + new ZplBarcode93("Barcode93", 10, 300), + new ZplBarcodeAnsiCodabar("123456", 'a', 'd', 10, 450, 100), + new ZplBarcodeEan13("123456789", 10, 600), + new ZplBarcodeInterleaved2of5("123456789", 10, 750), + new ZplQrCode("BinaryKits ZplUtility BinaryKits ZplUtility BinaryKits ZplUtility", 10, 950, magnificationFactor: 6) }; var renderEngine = new ZplEngine(elements); @@ -192,7 +193,7 @@ static string RenderLabel6() new ZplTextBlock(text, 10, 120, 400, 100, font1, NewLineConversionMethod.ToSpace), new ZplTextBlock(text, 10, 240, 400, 100, font2, NewLineConversionMethod.ToEmpty), - + new ZplFieldBlock(text, 10, 360, 400, font1, 4) }; diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs new file mode 100644 index 00000000..0e657a63 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/Code93BarcodeZplCommandAnalyzer.cs @@ -0,0 +1,55 @@ +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Models; + +namespace BinaryKits.Zpl.Viewer.CommandAnalyzers +{ + public class Code93BarcodeZplCommandAnalyzer : ZplCommandAnalyzerBase + { + public Code93BarcodeZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^BA", virtualPrinter) { } + + /// + public override ZplElementBase Analyze(string zplCommand) + { + var zplDataParts = this.SplitCommand(zplCommand); + + int tmpint; + bool printCheckDigit = false; + int height = this.VirtualPrinter.BarcodeInfo.Height; + bool printInterpretationLine = true; + bool printInterpretationLineAboveCode = false; + + var 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]); + } + + //The field data are processing in the FieldDataZplCommandAnalyzer + this.VirtualPrinter.SetNextElementFieldData(new Code93BarcodeFieldData + { + FieldOrientation = fieldOrientation, + Height = height, + PrintInterpretationLine = printInterpretationLine, + PrintInterpretationLineAboveCode = printInterpretationLineAboveCode, + PrintCheckDigit = printCheckDigit + }); + + return null; + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs index ba6aa0bb..3f0b9f68 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, string prefix="^FD") : base(prefix, virtualPrinter) { } + public FieldDataZplCommandAnalyzer(VirtualPrinter virtualPrinter, string prefix = "^FD") : base(prefix, virtualPrinter) { } /// public override ZplElementBase Analyze(string zplCommand) @@ -53,6 +53,10 @@ public override ZplElementBase Analyze(string zplCommand) { return new ZplBarcode39(text, x, y, code39.Height, moduleWidth, wideBarToNarrowBarWidthRatio, code39.FieldOrientation, code39.PrintInterpretationLine, code39.PrintInterpretationLineAboveCode, code39.Mod43CheckDigit, bottomToTop: bottomToTop); } + 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); + } 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); @@ -103,7 +107,7 @@ public override ZplElementBase Analyze(string zplCommand) 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, reversePrint: reversePrint, bottomToTop: bottomToTop); } return new ZplTextField(text, x, y, font, reversePrint: reversePrint, bottomToTop: bottomToTop); diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs new file mode 100644 index 00000000..a0905e49 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs @@ -0,0 +1,57 @@ +using BarcodeLib; +using BinaryKits.Zpl.Label.Elements; +using BinaryKits.Zpl.Viewer.Helpers; +using SkiaSharp; +using System; +using System.Drawing; + +namespace BinaryKits.Zpl.Viewer.ElementDrawers +{ + public class Barcode93ElementDrawer : BarcodeDrawerBase + { + /// + public override bool CanDraw(ZplElementBase element) + { + return element is ZplBarcode93; + } + + /// + public override void Draw(ZplElementBase element) + { + Draw(element, new DrawerOptions()); + } + + /// + public override void Draw(ZplElementBase element, DrawerOptions options) + { + if (element is ZplBarcode93 barcode) + { + float x = barcode.PositionX; + float y = barcode.PositionY; + + var content = barcode.Content; + var interpretation = string.Format("*{0}*", content.Trim('*')); + + float labelFontSize = Math.Min(barcode.ModuleWidth * 7.2f, 72f); + var labelTypeFace = options.FontLoader("A"); + var labelFont = new SKFont(labelTypeFace, labelFontSize).ToSystemDrawingFont(); + int labelHeight = barcode.PrintInterpretationLine ? labelFont.Height : 0; + int labelHeightOffset = barcode.PrintInterpretationLineAboveCode ? labelHeight : 0; + + var barcodeElement = new Barcode + { + BarWidth = barcode.ModuleWidth, + BackColor = Color.Transparent, + Height = barcode.Height + labelHeight, + IncludeLabel = barcode.PrintInterpretationLine, + LabelPosition = barcode.PrintInterpretationLineAboveCode ? LabelPositions.TOPCENTER : LabelPositions.BOTTOMCENTER, + LabelFont = labelFont, + AlternateLabel = interpretation + }; + + using var image = barcodeElement.Encode(TYPE.CODE93, content); + this.DrawBarcode(this.GetImageData(image), barcode.Height, image.Width, barcode.FieldOrigin != null, x, y, labelHeightOffset, barcode.FieldOrientation); + } + } + } +} diff --git a/src/BinaryKits.Zpl.Viewer/Models/Code93BarcodeFieldData.cs b/src/BinaryKits.Zpl.Viewer/Models/Code93BarcodeFieldData.cs new file mode 100644 index 00000000..6eb7ee62 --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer/Models/Code93BarcodeFieldData.cs @@ -0,0 +1,13 @@ +using BinaryKits.Zpl.Label; + +namespace BinaryKits.Zpl.Viewer.Models +{ + internal class Code93BarcodeFieldData : 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/ZplAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs index 602157f8..e8a5927b 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplAnalyzer.cs @@ -38,6 +38,7 @@ public AnalyzeInfo Analyze(string zplData) 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), @@ -156,7 +157,8 @@ private string[] SplitZplCommands(string zplData) var commandLetters = command.Substring(1, 2).ToUpper(); - if (ignoredCommandsHS.Contains(commandLetters)) { + if (ignoredCommandsHS.Contains(commandLetters)) + { continue; } else if (commandLetters == "CT") @@ -166,12 +168,15 @@ private string[] SplitZplCommands(string zplData) else if (commandLetters == "CC") { caret = command[3]; - } else { + } + else + { results.Add(command); } } // likely invalid command - else if (command.Trim().Length > 0) { + 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 diff --git a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs index 018ea03e..d1583750 100644 --- a/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ZplElementDrawer.cs @@ -26,6 +26,7 @@ public ZplElementDrawer(IPrinterStorage printerStorage, DrawerOptions drawerOpti { new Barcode128ElementDrawer(), new Barcode39ElementDrawer(), + new Barcode93ElementDrawer(), new BarcodeEAN13ElementDrawer(), new DataMatrixElementDrawer(), new FieldBlockElementDrawer(), @@ -58,7 +59,7 @@ public byte[] Draw( { return this.DrawMulti(elements, labelWidth, labelHeight, printDensityDpmm)[0]; } - + /// /// Draw the label as PDF /// @@ -94,7 +95,7 @@ public List DrawMulti( var imageHistory = new List(); var labelImageWidth = Convert.ToInt32(labelWidth * printDensityDpmm); var labelImageHeight = Convert.ToInt32(labelHeight * printDensityDpmm); - + //use SKNWayCanvas to be able to draw on multiple canvases using var skCanvas = new SKNWayCanvas(labelImageWidth, labelImageHeight); @@ -103,7 +104,7 @@ public List DrawMulti( var surface = SKSurface.Create(info); using var 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(); @@ -113,7 +114,7 @@ public List DrawMulti( { skCanvas.AddCanvas(pdfCanvas); } - + //make sure to have a transparent canvas for SKBlendMode.Xor to work properly skCanvas.Clear(SKColors.Transparent); @@ -149,16 +150,16 @@ public List DrawMulti( using var skBitmapInvert = new SKBitmap(labelImageWidth, labelImageHeight); using var skCanvasInvert = new SKCanvas(skBitmapInvert); skCanvasInvert.Clear(SKColors.Transparent); - + drawer.Prepare(this._printerStorage, skCanvasInvert); drawer.Draw(element, _drawerOptions); - + //save state before inverted draw if (this._drawerOptions.PdfOutput == true) { imageHistory.Add(surface.Snapshot()); } - + //use color inversion on an reverse draw white element if (drawer.IsWhiteDraw(element)) { @@ -168,7 +169,7 @@ public List DrawMulti( { this.InvertDraw(skCanvas, skBitmapInvert); } - + continue; } @@ -197,12 +198,12 @@ public List DrawMulti( using var surfaceWhiteBg = SKSurface.Create(info); using var skImageCanvasWhiteBg = surfaceWhiteBg.Canvas; skImageCanvasWhiteBg.Clear(SKColors.White); - + var surfaceImage = surface.Snapshot(); var paint = new SKPaint(); paint.BlendMode = SKBlendMode.SrcOver; skImageCanvasWhiteBg.DrawImage(surfaceImage, 0f, 0f, paint); - + image = surfaceWhiteBg.Snapshot(); } @@ -248,7 +249,7 @@ private void FixPdfInvertDraw(SKImageInfo info, List imageHistory, SKSu using var surfacePdfInvertColorFix = SKSurface.Create(info); using var skImageCanvasPdfInvertColorFix = surfacePdfInvertColorFix.Canvas; skImageCanvasPdfInvertColorFix.Clear(SKColors.Transparent); - + //make an image of everything that was once colored foreach (var imageHistoryState in imageHistory) { @@ -256,13 +257,13 @@ private void FixPdfInvertDraw(SKImageInfo info, List imageHistory, SKSu pdfPaint.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; 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); @@ -286,7 +287,7 @@ private void InvertDraw(SKCanvas baseCanvas, SKBitmap bmToInvert) baseCanvas.DrawBitmap(bmToInvert, 0, 0, paint); } } - + private void InvertDrawWhite(SKCanvas baseCanvas, SKBitmap bmToInvert) { using (SKPaint paint = new SKPaint()) From 10059c803355717f89ae10eafc20c640d6c79ac3 Mon Sep 17 00:00:00 2001 From: primo-ppcg Date: Tue, 23 Apr 2024 18:31:47 +0700 Subject: [PATCH 2/2] Update Code93 Update interpretation line Add test to WebApi --- .../Labels/Test/Barcode93-102x152.zpl2 | 18 ++++++++++++++++++ .../ElementDrawers/Barcode93ElementDrawer.cs | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 new file mode 100644 index 00000000..c962c23a --- /dev/null +++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/Barcode93-102x152.zpl2 @@ -0,0 +1,18 @@ +^XA + +^FO10,10 +^BY3,2 +^BAN,100,Y,N +^FD123ABC^FS + +^FO10,160 +^BY4,2 +^BAN,100,Y,N +^FD123ABC^FS + +^FO10,320 +^BY5,2 +^BAN,100,Y,N +^FD123ABC^FS + +^XZ \ No newline at end of file diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs index a0905e49..3cd44bd9 100644 --- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs +++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode93ElementDrawer.cs @@ -30,7 +30,6 @@ public override void Draw(ZplElementBase element, DrawerOptions options) float y = barcode.PositionY; var content = barcode.Content; - var interpretation = string.Format("*{0}*", content.Trim('*')); float labelFontSize = Math.Min(barcode.ModuleWidth * 7.2f, 72f); var labelTypeFace = options.FontLoader("A"); @@ -46,7 +45,7 @@ public override void Draw(ZplElementBase element, DrawerOptions options) IncludeLabel = barcode.PrintInterpretationLine, LabelPosition = barcode.PrintInterpretationLineAboveCode ? LabelPositions.TOPCENTER : LabelPositions.BOTTOMCENTER, LabelFont = labelFont, - AlternateLabel = interpretation + AlternateLabel = content }; using var image = barcodeElement.Encode(TYPE.CODE93, content);