Skip to content

Instantly share code, notes, and snippets.

@mwiemarc
Created October 16, 2021 20:27
Show Gist options
  • Save mwiemarc/976e490d42e1cff0e367c2eb7ebc863a to your computer and use it in GitHub Desktop.
Save mwiemarc/976e490d42e1cff0e367c2eb7ebc863a to your computer and use it in GitHub Desktop.
Custom XML Markup Interpreter to ESCPOS_NET commands
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