-
-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #190 from reportingissue/pdf417
Add Pdf417 barcode support
- Loading branch information
Showing
7 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace BinaryKits.Zpl.Label.Elements | ||
{ | ||
/// <summary> | ||
/// PDF417 Barcode ^B7o,h,s,c,r,t | ||
/// </summary> | ||
public class ZplPDF417 : ZplPositionedElementBase, IFormatElement | ||
{ | ||
|
||
public int Height { 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; } | ||
public int SecurityLevel { get; protected set; } | ||
|
||
/// <summary> | ||
/// Zpl PDF417 barcode | ||
/// </summary> | ||
/// <param name="content"></param> | ||
/// <param name="positionX"></param> | ||
/// <param name="positionY"></param> | ||
/// <param name="height"></param> | ||
/// <param name="columns">1-30: Number of data columns to encode. Default will auto balance 1:2 row to column</param> | ||
/// <param name="rows">3-90. Number of data columns to encode. Default will auto balance 1:2 row to column</param> | ||
/// <param name="compact">Truncate right row indicators and stop pattern</param> | ||
/// <param name="fieldOrientation"></param> | ||
/// <param name="securityLevel">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.</param> | ||
/// <param name="bottomToTop"></param> | ||
public ZplPDF417( | ||
string content, | ||
int positionX, | ||
int positionY, | ||
int height = 8, | ||
int? columns = null, | ||
int? rows = null, | ||
bool compact = false, | ||
int securityLevel = 0, | ||
FieldOrientation fieldOrientation = FieldOrientation.Normal, | ||
bool bottomToTop = false | ||
) | ||
: base(positionX, positionY, bottomToTop) | ||
{ | ||
FieldOrientation = fieldOrientation; | ||
Height = height; | ||
Columns = columns; | ||
Rows = rows; | ||
Compact = compact; | ||
SecurityLevel = securityLevel; | ||
Content = content; | ||
} | ||
|
||
|
||
protected string RenderFieldOrientation() | ||
{ | ||
return RenderFieldOrientation(FieldOrientation); | ||
} | ||
|
||
///<inheritdoc/> | ||
public override IEnumerable<string> Render(ZplRenderOptions context) | ||
{ | ||
//^ FO100,100 | ||
//^ BQN,2,10 | ||
//^ FDMM,AAC - 42 ^ FS | ||
var result = new List<string>(); | ||
result.AddRange(RenderPosition(context)); | ||
result.Add($"^BX{RenderFieldOrientation()},{context.Scale(Height)}"); | ||
result.Add($"^FD{Content}^FS"); | ||
|
||
return result; | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void SetTemplateContent(string content) | ||
{ | ||
Content = content; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
src/BinaryKits.Zpl.Viewer/CommandAnalyzers/PDF417BarcodeCommandAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using BinaryKits.Zpl.Label; | ||
using BinaryKits.Zpl.Label.Elements; | ||
using BinaryKits.Zpl.Viewer.Models; | ||
using System; | ||
|
||
namespace BinaryKits.Zpl.Viewer.CommandAnalyzers | ||
{ | ||
public class PDF417ZplCommandAnalyzer : ZplCommandAnalyzerBase | ||
{ | ||
public PDF417ZplCommandAnalyzer(VirtualPrinter virtualPrinter) : base("^B7", virtualPrinter) { } | ||
///<inheritdoc/> | ||
public override ZplElementBase Analyze(string zplCommand) | ||
{ | ||
var zplDataParts = this.SplitCommand(zplCommand); | ||
|
||
// reusable buffer | ||
int tmpint; | ||
|
||
/* | ||
* Format: ^B7o,h,s,c,r,t, parse order: | ||
* orientation | ||
* height | ||
* security level | ||
* columns | ||
* rows | ||
* compact | ||
*/ | ||
|
||
var fieldOrientation = this.ConvertFieldOrientation(zplDataParts[0]); | ||
|
||
int height = this.VirtualPrinter.BarcodeInfo.Height; | ||
if (zplDataParts.Length > 1 && int.TryParse(zplDataParts[1], out tmpint)) | ||
{ | ||
height = tmpint; | ||
} | ||
|
||
int securityLevel = 0; | ||
if (zplDataParts.Length > 2 && int.TryParse(zplDataParts[2], out tmpint)) | ||
{ | ||
securityLevel = tmpint; | ||
} | ||
|
||
int? columns = null; | ||
if (zplDataParts.Length > 3 && int.TryParse(zplDataParts[3], out tmpint)) | ||
{ | ||
columns = tmpint; | ||
} | ||
|
||
int? rows = null; | ||
if (zplDataParts.Length > 4 && int.TryParse(zplDataParts[4], out tmpint)) | ||
{ | ||
rows = tmpint; | ||
} | ||
|
||
bool compact = false; | ||
if (zplDataParts.Length > 5) | ||
{ | ||
compact = ConvertBoolean(zplDataParts[5]); | ||
} | ||
|
||
//The field data are processing in the FieldDataZplCommandAnalyzer | ||
this.VirtualPrinter.SetNextElementFieldData(new PDF417FieldData | ||
{ | ||
FieldOrientation = fieldOrientation, | ||
Height = height, | ||
SecurityLevel = securityLevel, | ||
Columns = columns, | ||
Rows = rows, | ||
Compact = compact | ||
}); | ||
|
||
return null; | ||
} | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
src/BinaryKits.Zpl.Viewer/ElementDrawers/PDF417ElementDrawer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
using BinaryKits.Zpl.Label; | ||
using BinaryKits.Zpl.Label.Elements; | ||
using SkiaSharp; | ||
using System; | ||
using System.Collections.Generic; | ||
using ZXing; | ||
using ZXing.Common; | ||
using ZXing.PDF417; | ||
using ZXing.PDF417.Internal; | ||
|
||
namespace BinaryKits.Zpl.Viewer.ElementDrawers | ||
{ | ||
/// <summary> | ||
/// Drawer for PDF417 Barcode elements | ||
/// </summary> | ||
public class Pdf417ElementDrawer : BarcodeDrawerBase | ||
{ | ||
///<inheritdoc/> | ||
public override bool CanDraw(ZplElementBase element) | ||
{ | ||
return element is ZplPDF417; | ||
} | ||
|
||
///<inheritdoc/> | ||
public override void Draw(ZplElementBase element) | ||
{ | ||
if (element is ZplPDF417 pdf417) | ||
{ | ||
if (pdf417.Height == 0) | ||
throw new System.Exception("PDF417 Height is set to zero."); | ||
|
||
if (string.IsNullOrWhiteSpace(pdf417.Content)) | ||
throw new System.Exception("PDF147 Content is empty."); | ||
|
||
float x = pdf417.PositionX; | ||
float y = pdf417.PositionY; | ||
|
||
int mincols, maxcols, minrows, maxrows; | ||
if (pdf417.Rows != null) | ||
{ | ||
minrows = pdf417.Rows.Value; | ||
maxrows = pdf417.Rows.Value; | ||
} | ||
else | ||
{ | ||
minrows = 3; | ||
maxrows = 90; | ||
} | ||
|
||
if (pdf417.Columns != null) | ||
{ | ||
mincols = pdf417.Columns.Value; | ||
maxcols = pdf417.Columns.Value; | ||
} | ||
else | ||
{ | ||
mincols = 1; | ||
maxcols = 30; | ||
} | ||
var writer = new PDF417Writer(); | ||
var hints = new Dictionary<EncodeHintType, object> { | ||
{ EncodeHintType.CHARACTER_SET, "UTF-8" }, | ||
{ 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.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); | ||
|
||
using var resizedImage = this.BitMatrixToSKBitmap(result, 1); | ||
{ | ||
var png = resizedImage.Encode(SKEncodedImageFormat.Png, 100).ToArray(); | ||
this.DrawBarcode(png, resizedImage.Height, resizedImage.Width, pdf417.FieldOrigin != null, x, y, 0, pdf417.FieldOrientation); | ||
} | ||
} | ||
} | ||
|
||
// bitmatrix scaling instead of bitmap | ||
private BitMatrix proportional_upscale(BitMatrix old, int scale) { | ||
if (scale == 0 || scale == 1) | ||
{ | ||
return old; | ||
} | ||
BitMatrix upscaled = new BitMatrix(old.Width * scale, old.Height * scale); | ||
for (int i = 0; i < old.Height; i++) | ||
{ | ||
BitArray old_row = old.getRow(i, null); | ||
for (int j = 0; j < old.Width; j++) | ||
{ | ||
bool is_set = old_row[j]; | ||
if (!is_set) | ||
{ | ||
continue; | ||
} | ||
upscaled.setRegion(j * scale, i * scale, scale, scale); | ||
} | ||
} | ||
return upscaled; | ||
} | ||
|
||
// needed to match 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; | ||
int width = old_matrix.Width; | ||
int rows = old_matrix.Height / old_bar_height; // logical rows; | ||
|
||
if (new_bar_height == old_bar_height || new_bar_height == 0) | ||
{ | ||
return old_matrix; | ||
} | ||
|
||
BitMatrix scaled = new BitMatrix(old_matrix.Width, rows * new_bar_height); | ||
|
||
for (int i = 0; i < rows; i++) | ||
{ | ||
BitArray old_row = old_matrix.getRow(i * old_bar_height, null); | ||
for (int j = 0; j < width; j++) | ||
{ | ||
bool is_set = old_row[j]; | ||
if (!is_set) | ||
{ | ||
continue; | ||
} | ||
scaled.setRegion(j, i * new_bar_height, 1, new_bar_height); | ||
} | ||
} | ||
return scaled; | ||
} | ||
|
||
private PDF417ErrorCorrectionLevel ConvertErrorCorrection(int correction) | ||
{ | ||
return correction switch | ||
{ | ||
0 => PDF417ErrorCorrectionLevel.L0, | ||
1 => PDF417ErrorCorrectionLevel.L1, | ||
2 => PDF417ErrorCorrectionLevel.L2, | ||
3 => PDF417ErrorCorrectionLevel.L3, | ||
4 => PDF417ErrorCorrectionLevel.L4, | ||
5 => PDF417ErrorCorrectionLevel.L5, | ||
6 => PDF417ErrorCorrectionLevel.L6, | ||
7 => PDF417ErrorCorrectionLevel.L7, | ||
8 => PDF417ErrorCorrectionLevel.L8, | ||
_ => PDF417ErrorCorrectionLevel.AUTO, | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using BinaryKits.Zpl.Label; | ||
|
||
namespace BinaryKits.Zpl.Viewer.Models | ||
{ | ||
public class PDF417FieldData : FieldDataBase | ||
{ | ||
public int Height { get; set; } | ||
public FieldOrientation FieldOrientation { get; set; } | ||
public int? Columns { get; set; } | ||
public int? Rows { get; set; } | ||
public bool Compact { get; set; } | ||
public int SecurityLevel { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters