diff --git a/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs b/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs
index 74142c9b..41a231e7 100644
--- a/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs
+++ b/src/BinaryKits.Zpl.Label/Elements/ZplPDF417.cs
@@ -9,6 +9,7 @@ public class ZplPDF417 : ZplPositionedElementBase, IFormatElement
{
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; }
@@ -23,6 +24,7 @@ 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
@@ -34,6 +36,7 @@ public ZplPDF417(
int positionX,
int positionY,
int height = 8,
+ int moduleWidth = 2,
int? columns = null,
int? rows = null,
bool compact = false,
@@ -45,6 +48,7 @@ public ZplPDF417(
{
FieldOrientation = fieldOrientation;
Height = height;
+ ModuleWidth = moduleWidth;
Columns = columns;
Rows = rows;
Compact = compact;
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 5bee3af9..351dd746 100644
--- a/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj
+++ b/src/BinaryKits.Zpl.Viewer.WebApi/BinaryKits.Zpl.Viewer.WebApi.csproj
@@ -126,6 +126,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodePDF417-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodePDF417-102x152.zpl2
new file mode 100644
index 00000000..3401bb89
--- /dev/null
+++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/BarcodePDF417-102x152.zpl2
@@ -0,0 +1,104 @@
+^XA
+
+^FO10,10
+^BY1
+^B7N,4
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FX This one looks half-height on Zebra
+^FO120,10
+^BY1
+^B7N,4,,,,Y
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FX Difference for security level
+^FO10,90
+^BY1
+^B7N,4,3
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO120,90
+^BY1
+^B7N,4,4
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO250,90
+^BY1
+^B7N,4,5
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO400,90
+^BY1
+^B7N,4,6
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FX Labelary is wrong on this one
+^FO570,90
+^BY1
+^B7N,4,6,,,Y
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO10,210
+^BY1
+^B7N,4,5,6
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO210,210
+^BY1
+^B7N,4,5,6,20
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FX Difference for missing columns
+^FO10,300
+^BY1
+^B7N,4,5,8,24,N
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO250,300
+^BY1
+^B7N,4,5,,24,N
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FX DHL real-world test vs corrected
+^FO10,400
+^BY2
+^B7N,6.7,5,,30,N
+^FD
+UNH+2876965+IFTMIN:D:96B:UN+DHL5.6.0/AWESOME'BGM+787+999994760001+9'DTM+186:20240312:102'TSR+++10'TOD+Z02++CPT'NAD+OS+0464651'NAD+CN+++MEVR. SOME PERSONE+STREET 17 E+SOMEPLACE++0+DE'CTA+GR'COM+SOMEEMAIL@GMAIL.COM:EM'GID+0+1'MEA+WT++KGM:2'PCI+ZZ1+JVGL09999999999994760001'UNT+13+123546798'
+^FS
+
+^FX Difference in blocks between all three sources. (This, Zebra and Labelary)
+^FO10,590
+^BY2
+^B7N,6,5,9,30,N
+^FD
+UNH+2876965+IFTMIN:D:96B:UN+DHL5.6.0/AWESOME'BGM+787+999994760001+9'DTM+186:20240312:102'TSR+++10'TOD+Z02++CPT'NAD+OS+0464651'NAD+CN+++MEVR. SOME PERSONE+STREET 17 E+SOMEPLACE++0+DE'CTA+GR'COM+SOMEEMAIL@GMAIL.COM:EM'GID+0+1'MEA+WT++KGM:2'PCI+ZZ1+JVGL09999999999994760001'UNT+13+123546798'
+^FS
+
+^FX Difference in blocks with Labelary but not with Zebra printed result
+^FO10,780
+^BY2
+^B7N,4,5,6
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO380,780
+^BY2
+^B7N,4,5,6
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^FS
+
+^FO10,840
+^BY3
+^B7N,4,5,8,24,N
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO10,950
+^BY4
+^B7N,4,6,7,24,N
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^FO10,1060
+^BY5
+^B7N,4,6,4,36,N
+^FDABCDEFGHIJKLMNOPQRSTUVWXYZ^FS
+
+^XZ
\ No newline at end of file
diff --git a/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GS1-102x152.zpl2 b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GS1-102x152.zpl2
new file mode 100644
index 00000000..0e3fc7f1
--- /dev/null
+++ b/src/BinaryKits.Zpl.Viewer.WebApi/Labels/Test/GS1-102x152.zpl2
@@ -0,0 +1,18 @@
+^XA
+
+^FX all should produce 011234567890123121123456
+
+^FT101,59^A0N,31,30^FH\^CI28^FDGS1-128 : ^FS^CI27
+^BY2,3,54^FT110,134^BCN,,N,N
+^FH\^FD>;>8011234567890123121123456^FS
+
+^FT101,174^A0N,31,30^FH\^CI28^FDGS1-DataMatrix : ^FS^CI27
+^FT185,324^BXN,6,200,0,0,1,_,1
+^FH\^FD_1011234567890123121123456^FS
+
+^FT548,174^A0N,31,30^FH\^CI28^FDGS1-QR: ^FS^CI27
+^FO642,206^BQN,2,5
+^FH\^FD>;>8011234567890123121123456^FS
+
+^PQ1,0,1,Y
+^XZ
\ No newline at end of file
diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs
index 0121a75f..2e35d1f4 100644
--- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs
+++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/FieldDataZplCommandAnalyzer.cs
@@ -78,7 +78,7 @@ public override ZplElementBase Analyze(string zplCommand)
}
if (this.VirtualPrinter.NextElementFieldData is PDF417FieldData pdf147)
{
- return new ZplPDF417(text, x, y, pdf147.Height, pdf147.Columns, pdf147.Rows, pdf147.Compact, pdf147.SecurityLevel, pdf147.FieldOrientation, bottomToTop);
+ return new ZplPDF417(text, x, y, pdf147.Height, moduleWidth, pdf147.Columns, pdf147.Rows, pdf147.Compact, pdf147.SecurityLevel, pdf147.FieldOrientation, bottomToTop);
}
}
diff --git a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs
index 28cfd388..6d696c90 100644
--- a/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs
+++ b/src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs
@@ -2,6 +2,7 @@
using BinaryKits.Zpl.Label.Elements;
using BinaryKits.Zpl.Viewer.Models;
using System;
+using System.Globalization;
namespace BinaryKits.Zpl.Viewer.CommandAnalyzers
{
@@ -33,6 +34,16 @@ public override ZplElementBase Analyze(string zplCommand)
{
height = tmpint;
}
+ 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);
+ if (tempHeight > 0)
+ {
+ height = tempHeight;
+ }
+ }
int securityLevel = 0;
if (zplDataParts.Length > 2 && int.TryParse(zplDataParts[2], out tmpint))
diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs
index 5bcd5e0c..fdc542a0 100644
--- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs
+++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/Barcode128ElementDrawer.cs
@@ -3,7 +3,6 @@
using BinaryKits.Zpl.Viewer.Helpers;
using SkiaSharp;
using System;
-using System.Collections.Generic;
using System.Drawing;
using System.Text.RegularExpressions;
@@ -11,20 +10,12 @@ namespace BinaryKits.Zpl.Viewer.ElementDrawers
{
public class Barcode128ElementDrawer : BarcodeDrawerBase
{
-
///
/// Start sequence lookups.
///
///
- private static readonly Dictionary startCodeMap = new Dictionary()
- {
- { ">9", TYPE.CODE128A },
- { ">:", TYPE.CODE128B },
- { ">;", TYPE.CODE128C }
- };
-
- private static readonly Regex startCodeRegex = new Regex(@"^(>[9:;])(.+)$", RegexOptions.Compiled);
- private static readonly Regex invalidInvocationRegex = new Regex(@"(?[9:;]", RegexOptions.Compiled);
+ private static readonly Regex startCodeRegex = new Regex(@"(>[9:;])", RegexOptions.Compiled);
+ private static readonly Regex invalidInvocationRegex = new Regex(@"(?[<0=12345679:;]", RegexOptions.Compiled); //>8 has limited support here
// As defined in BarcodeLib.Symbologies.Code128
private static readonly string FNC1 = Convert.ToChar(200).ToString();
@@ -46,33 +37,42 @@ public override void Draw(ZplElementBase element, DrawerOptions options)
{
if (element is ZplBarcode128 barcode)
{
- var barcodeType = TYPE.CODE128B;
- // remove any start sequences not at the start of the content (invalid invocation)
- string content = invalidInvocationRegex.Replace(barcode.Content, "");
+ var barcodeType = TYPE.CODE128;
+
+ //remove the start code form the content we only support the globals N,A,D,U and our barcode library doesn't support these types
+ string content = startCodeRegex.Replace(barcode.Content, "");
string interpretation = content;
+
+ // remove any start sequences not at the start of the content (invalid invocation)
+ content = invalidInvocationRegex.Replace(content, "");
+ interpretation = content;
+
+ // support hand-rolled GS1
+ content = content.Replace(">8", FNC1);
+ interpretation = interpretation.Replace(">8", "");
+
if (string.IsNullOrEmpty(barcode.Mode) || barcode.Mode == "N")
{
- Match startCodeMatch = startCodeRegex.Match(content);
- if (startCodeMatch.Success)
- {
- barcodeType = startCodeMap[startCodeMatch.Groups[1].Value];
- content = startCodeMatch.Groups[2].Value;
- interpretation = content;
- }
- // support hand-rolled GS1
- content = content.Replace(">8", FNC1);
- interpretation = interpretation.Replace(">8", "");
- // TODO: support remaining escapes within a barcode
+ barcodeType = TYPE.CODE128; // dynamic
+ //TODO: Instead of using the auto type, switch type for each part of the content
+ // - Current library doesn't support that.
+ //>:+B210AC>50270>6/$+2>5023080000582>6L
+ //[TYPE.CODE128B]+B210AC
+ //[TYPE.CODE128C]0270
+ //[TYPE.CODE128B]+/$+2
+ //[TYPE.CODE128C]023080000582
+ //[TYPE.CODE128B]L
}
else if (barcode.Mode == "A")
{
+ //A (automatic mode, the ZPL engine automatically determines the subsets that are used to encode the data)
barcodeType = TYPE.CODE128; // dynamic
}
else if (barcode.Mode == "D")
{
+ //D (UCC/EAN mode, field data must contain GS1 numbers)
barcodeType = TYPE.CODE128C;
- content = content.Replace(">8", FNC1);
- interpretation = interpretation.Replace(">8", "");
+
if (!content.StartsWith(FNC1))
{
content = FNC1 + content;
@@ -80,6 +80,7 @@ public override void Draw(ZplElementBase element, DrawerOptions options)
}
else if (barcode.Mode == "U")
{
+ //U (UCC case mode, field data must contain 19 digits)
barcodeType = TYPE.CODE128C;
content = content.PadLeft(19, '0').Substring(0, 19);
int checksum = 0;
diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs
index d2cf127e..adc92990 100644
--- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs
+++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/DataMatrixElementDrawer.cs
@@ -1,6 +1,7 @@
using BinaryKits.Zpl.Label.Elements;
using SkiaSharp;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using ZXing;
using ZXing.Datamatrix;
using ZXing.Datamatrix.Encoder;
@@ -29,11 +30,22 @@ public override void Draw(ZplElementBase element)
float x = dataMatrix.PositionX;
float y = dataMatrix.PositionY;
+ // support hand-rolled GS1
+ bool gs1Mode = false;
+ var content = dataMatrix.Content;
+ if (Regex.Match(content, @"(^_1)", RegexOptions.None).Success)
+ {
+ content = Regex.Replace(content, @"(^_1)", "");
+ gs1Mode = true;
+ }
+
var writer = new DataMatrixWriter();
var hints = new Dictionary {
- { EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE }
+ { EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE },
+ { EncodeHintType.DATA_MATRIX_COMPACT, gs1Mode },
+ { EncodeHintType.GS1_FORMAT, gs1Mode }
};
- var result = writer.encode(dataMatrix.Content, BarcodeFormat.DATA_MATRIX, 0, 0, hints);
+ var result = writer.encode(content, BarcodeFormat.DATA_MATRIX, 0, 0, hints);
using var resizedImage = this.BitMatrixToSKBitmap(result, dataMatrix.Height);
{
diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs
index c96348dc..3c2d4b30 100644
--- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs
+++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs
@@ -56,26 +56,37 @@ public override void Draw(ZplElementBase element)
{
mincols = 1;
maxcols = 30;
+
+ if (pdf417.Rows != null)
+ {
+ //When column count isn't defined, and rows count is,
+ // the col/row ratio is calculated using the algorithm in: ZXing.PDF417.Internal.PDF417.determineDimensions
+ // to allow a range for that algorithm, we divide the given row amount by 2.
+ // as the algorithm goes from highest to lowest, this usually produces an acceptable result
+ minrows /= 2;
+ }
}
var writer = new PDF417Writer();
var hints = new Dictionary {
- { EncodeHintType.CHARACTER_SET, "UTF-8" },
+ // { EncodeHintType.CHARACTER_SET, "ISO-8859-1" },
{ EncodeHintType.PDF417_COMPACT, pdf417.Compact },
//{ EncodeHintType.PDF417_AUTO_ECI, true },
//{ EncodeHintType.DISABLE_ECI, true },
{ EncodeHintType.PDF417_COMPACTION, Compaction.AUTO},
- { EncodeHintType.PDF417_ASPECT_RATIO, 3 }, // height of a single bar relative to width
- { EncodeHintType.PDF417_IMAGE_ASPECT_RATIO, 2.0f }, // zpl default, proportions of columns to rows
+ { EncodeHintType.PDF417_ASPECT_RATIO, PDF417AspectRatio.A3 }, // height of a single bar relative to width
+ { EncodeHintType.PDF417_IMAGE_ASPECT_RATIO, 1.0f }, // zpl default 2.0f, proportions of columns to rows //1.0f looks closer to printed Zebra label
{ EncodeHintType.MARGIN, 0 }, // its an int
{ 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);
-
- var upscaled = proportional_upscale(default_bitmatrix, 3);
- var result = vertical_scale(upscaled, pdf417.Height);
-
+
+ //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);
{
var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray();
@@ -107,14 +118,12 @@ private BitMatrix proportional_upscale(BitMatrix old, int scale) {
return upscaled;
}
- // needed to match labelary
+ // needed to match zebra and labelary
// zebra assumptions:
// - we can only set the height in zpl in points, not the width
- // - each bar is 3 "points" thick, until ^BY is implemented
- // - because we have PDF417_ASPECT_RATIO set to 3, and upscaling to 3, the height of a single bar is now 9
- // we only need to scale to the bar height/9
- private BitMatrix vertical_scale(BitMatrix old_matrix, int new_bar_height) {
- int old_bar_height = 9;
+ // - 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) {
int width = old_matrix.Width;
int rows = old_matrix.Height / old_bar_height; // logical rows;
diff --git a/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs b/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs
index 2fdb1316..38fcf52d 100644
--- a/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs
+++ b/src/BinaryKits.Zpl.Viewer/ElementDrawers/QrCodeElementDrawer.cs
@@ -2,6 +2,7 @@
using BinaryKits.Zpl.Label.Elements;
using SkiaSharp;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using ZXing;
using ZXing.QrCode;
@@ -22,6 +23,15 @@ public override void Draw(ZplElementBase element)
{
float x = qrcode.PositionX;
float y = qrcode.PositionY;
+
+ // support hand-rolled GS1
+ bool gs1Mode = false;
+ var content = qrcode.Content;
+ if (Regex.Match(content, @"(^>;>8)", RegexOptions.None).Success)
+ {
+ content = Regex.Replace(content, @"(^>;>8)", "");
+ gs1Mode = true;
+ }
int verticalQuietZone = 10;
@@ -30,9 +40,10 @@ public override void Draw(ZplElementBase element)
{ EncodeHintType.ERROR_CORRECTION, CovertErrorCorrection(qrcode.ErrorCorrectionLevel) },
{ EncodeHintType.QR_MASK_PATTERN, qrcode.MaskValue },
{ EncodeHintType.CHARACTER_SET, "UTF-8" },
- { EncodeHintType.MARGIN, 0 }
+ { EncodeHintType.MARGIN, 0 },
+ { EncodeHintType.GS1_FORMAT, gs1Mode }
};
- var result = writer.encode(qrcode.Content, BarcodeFormat.QR_CODE, 0, 0, hints);
+ var result = writer.encode(content, BarcodeFormat.QR_CODE, 0, 0, hints);
using var resizedImage = this.BitMatrixToSKBitmap(result, qrcode.MagnificationFactor);