Created
October 16, 2021 20:27
-
-
Save mwiemarc/976e490d42e1cff0e367c2eb7ebc863a to your computer and use it in GitHub Desktop.
Custom XML Markup Interpreter to ESCPOS_NET commands
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
using System; | |
using System.Collections.Generic; | |
using System.Drawing; | |
using System.Drawing.Imaging; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
using System.Xml.Linq; | |
using ESCPOS_NET; | |
using ESCPOS_NET.Emitters; | |
using ESCPOS_NET.Utilities; | |
namespace escpos_guiprt { | |
public class XMLRecieptInterpreter { | |
private readonly EPSON e = new EPSON(); | |
private XDocument doc; | |
private int dpl; | |
public XMLRecieptInterpreter(int dpl = -1) { | |
this.dpl = dpl; | |
} | |
public byte[] ParseString(string xmlStr) { | |
xmlStr = xmlStr.Trim().Replace("\r\n", "\n"); | |
if (xmlStr.Length < 1) // empty post data | |
return null; | |
//Console.WriteLine(xmlStr); | |
if (!xmlStr.StartsWith("<root")) // add root wrapper element | |
xmlStr = String.Format($"<root>{xmlStr}</root>"); | |
doc = XDocument.Parse(xmlStr); | |
return ParseDocument(); | |
} | |
public byte[] ParseFile(string fPath) { | |
if(!File.Exists(fPath)) | |
return null; | |
string str = File.ReadAllText(fPath); | |
if (str.Trim().Length < 1) // empty post data | |
return null; | |
//Console.WriteLine(str); | |
if (!str.StartsWith("<root")) // add root wrapper element | |
str = String.Format($"<root>{str.Trim()}</root>"); | |
doc = XDocument.Parse(str); | |
return ParseDocument(); | |
} | |
private byte[] ParseDocument() { | |
var root = doc.Element("root"); | |
if (root == null) | |
return null; | |
var dplAttr = root.Attribute("dpl"); | |
if (dplAttr != null) | |
int.TryParse(dplAttr.Value, out dpl); | |
var elements = root.Elements().ToArray<XElement>(); | |
var cmds = new List<byte[]>(); | |
foreach (XElement node in elements) { | |
var nCmds = ProcessNode(node); | |
if (nCmds == null) { | |
Console.WriteLine($"[WRN] Skipping '{node.Name.ToString().ToLower()}'-element due parsing failed"); | |
continue; | |
} | |
cmds.Add(nCmds); | |
} | |
return ByteSplicer.Combine(cmds.ToArray<byte[]>()); | |
} | |
private byte[] ProcessNode(XElement node) { | |
var nodeName = node.Name.ToString().ToLower(); | |
switch (nodeName) { | |
case "txt": | |
case "text": | |
return ByteSplicer.Combine(TextNodeHandler(node)); | |
case "nl": | |
case "newline": | |
return NewlineNodeHandler(node); | |
case "style": | |
case "styles": | |
return StylesNodeHandler(node); | |
case "align": | |
return AlignNodeHandler(node); | |
case "feed": | |
return FeedNodeHandler(node); | |
case "qr": | |
case "qrcode": | |
return QRNodeHandler(node); | |
case "img": | |
case "image": | |
return ImageNodeHandler(node); | |
case "flip": | |
return FlipNodeHandler(node); | |
default: | |
return null; | |
} | |
} | |
private byte[][] TextNodeHandler(XElement node) { | |
var val = node.Value.ToString(); | |
if (val.Length < 1) // empty node | |
return null; | |
var cmds = new List<byte[]>(); | |
var lines = Regex.Unescape(val).Split('\n'); | |
foreach (string line in lines) { | |
//Console.WriteLine($"TEXT>>{line}"); | |
cmds.Add(e.PrintLine(line)); | |
} | |
return cmds.ToArray<byte[]>(); | |
} | |
private byte[] AlignNodeHandler(XElement node) { | |
var val = node.Value.Trim().ToLower(); | |
if (val.Length < 1) | |
return null; // empty node | |
if (val == "left") | |
return e.LeftAlign(); | |
else if (val == "right") | |
return e.RightAlign(); | |
else if (val == "center") | |
return e.CenterAlign(); | |
return null; | |
} | |
private byte[] FeedNodeHandler(XElement node) { | |
var val = node.Value.Trim().ToLower(); | |
if (val.Length < 1) | |
return e.FeedLines(1); // empty node | |
int n = 1; | |
if (!int.TryParse(val, out n)) | |
return null; // empty node | |
return e.FeedLines(n); | |
} | |
private byte[] NewlineNodeHandler(XElement node) { | |
return e.PrintLine(""); | |
} | |
private byte[] QRNodeHandler(XElement node) { | |
var data = node.Value; | |
if (data.Length < 1) | |
return null; // empty node | |
var typeAttr = node.Attribute("type"); | |
var sizeAttr = node.Attribute("size"); | |
var crlevelAttr = node.Attribute("crlevel"); | |
var type = TwoDimensionCodeType.QRCODE_MODEL1; | |
var size = Size2DCode.NORMAL; | |
var crlevel = CorrectionLevel2DCode.PERCENT_25; | |
if (typeAttr != null) { | |
var typeVal = typeAttr.Value.ToLower(); | |
switch (typeVal) { | |
case "1": | |
case "model1": | |
default: | |
type = TwoDimensionCodeType.QRCODE_MODEL1; | |
break; | |
case "2": | |
case "model2": | |
type = TwoDimensionCodeType.QRCODE_MODEL2; | |
break; | |
case "3": | |
case "micro": | |
type = TwoDimensionCodeType.QRCODE_MICRO; | |
break; | |
case "4": | |
case "pdf": | |
type = TwoDimensionCodeType.PDF417; | |
break; | |
} | |
} | |
if (sizeAttr != null) { | |
var sizeVal = sizeAttr.Value.ToLower(); | |
if (sizeVal == "1") | |
size = Size2DCode.TINY; | |
else if (sizeVal == "2") | |
size = Size2DCode.SMALL; | |
else if (sizeVal == "3") | |
size = Size2DCode.NORMAL; | |
else if (sizeVal == "4") | |
size = Size2DCode.LARGE; | |
else if (sizeVal == "5") | |
size = Size2DCode.EXTRA; | |
} | |
if (crlevelAttr != null) { | |
var crlevelVal = crlevelAttr.Value.ToLower(); | |
if (crlevelVal == "1") | |
crlevel = CorrectionLevel2DCode.PERCENT_7; | |
else if (crlevelVal == "2") | |
crlevel = CorrectionLevel2DCode.PERCENT_15; | |
else if (crlevelVal == "3") | |
crlevel = CorrectionLevel2DCode.PERCENT_25; | |
else if (crlevelVal == "4") | |
crlevel = CorrectionLevel2DCode.PERCENT_30; | |
} | |
return e.PrintQRCode(data, type, size, crlevel); | |
} | |
private byte[] ImageNodeHandler(XElement node) { | |
var val = node.Value; | |
if (val.Length < 1) | |
return null; // empty node | |
var hidpiAttr = node.Attribute("hidpi"); | |
var legacyAttr = node.Attribute("legacy"); | |
var rotateAttr = node.Attribute("rotate"); | |
var invertAttr = node.Attribute("invert"); | |
var isLegacy = legacyAttr != null ? legacyAttr.Value.ToLower() == "true" : true; | |
var isHiDPI = hidpiAttr != null ? hidpiAttr.Value.ToLower() == "true" : false; | |
var isRotate = rotateAttr != null ? rotateAttr.Value.ToLower() == "true" : false; | |
var isInvert = invertAttr != null ? invertAttr.Value.ToLower() == "true" : false; | |
byte[] data; | |
if (val.StartsWith("data:image/")) { // base64 data | |
data = Convert.FromBase64String(val.Substring(val.IndexOf(";base64,") + 8)); // data:image/mediaType;base64, | |
} else if (val.StartsWith("http://") || val.StartsWith("https://")) { // image url | |
// fPath = ImageDownloadToFile(val); | |
throw new NotImplementedException("Error: image urls are not implemented yet"); | |
} else { // local file path | |
data = File.ReadAllBytes(val); | |
} | |
// process image | |
using (MemoryStream srcStream = new MemoryStream(data)) { // from byte array | |
using (Bitmap bmp = new Bitmap(srcStream)) { // create image object | |
if (isRotate) | |
bmp.RotateFlip(RotateFlipType.Rotate90FlipNone); // rotate 90deg clockwise | |
if (isInvert) { | |
for (int y = 0; (y <= (bmp.Height - 1)); y++) { | |
for (int x = 0; (x <= (bmp.Width - 1)); x++) { | |
System.Drawing.Color inv = bmp.GetPixel(x, y); | |
bmp.SetPixel(x, y, System.Drawing.Color.FromArgb(255, (255 - inv.R), (255 - inv.G), (255 - inv.B))); | |
} | |
} | |
} | |
using (MemoryStream outStream = new MemoryStream()) { // back to byte array | |
bmp.Save(outStream, ImageFormat.Bmp); | |
return ByteSplicer.Combine(e.PrintImage(outStream.ToArray(), isHiDPI, isLegacy, dpl)); | |
} | |
} | |
} | |
} | |
private byte[] FlipNodeHandler(XElement node) { | |
var val = node.Value.Trim().ToLower(); | |
if (val.Length < 1) | |
return null; // empty node | |
return e.UpsideDownMode(val == "true"); | |
} | |
private byte[] StylesNodeHandler(XElement node) { | |
var val = node.Value.Trim().ToLower(); | |
if (val.Length < 1) // empty node | |
return null; | |
var opts = GetValueOptions(val); | |
if (opts.Length == 0) | |
return null; | |
if (opts.Contains("none")) | |
return e.SetStyles(PrintStyle.None); | |
byte sum = 0; | |
if (opts.Contains("fontb") || opts.Contains("small")) | |
sum |= ((byte)PrintStyle.FontB); | |
else if (opts.Contains("bold")) | |
sum |= ((byte)PrintStyle.Bold); | |
else if (opts.Contains("doubleheight")) | |
sum |= ((byte)PrintStyle.DoubleHeight); | |
else if (opts.Contains("doublewidth")) | |
sum |= ((byte)PrintStyle.DoubleWidth); | |
else if (opts.Contains("underline")) | |
sum |= ((byte)PrintStyle.Underline); | |
return e.SetStyles((PrintStyle)sum); | |
} | |
private string[] GetValueOptions(string valueStr) { | |
var val = valueStr.Trim().ToLower(); | |
if (val.Length < 1) | |
return new string[0]; | |
var valArr = val.Split(','); | |
if (valArr.Length < 1) | |
return new string[0]; | |
return valArr; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment