ordersprinter/webapp/php/utilities/layouter.php

594 lines
16 KiB
PHP
Raw Normal View History

2020-11-19 23:14:48 +01:00
<?php
2020-11-19 23:15:07 +01:00
defined('LAYOUTER_HTML_MODE') || define ( 'LAYOUTER_HTML_MODE','0' );
2020-11-19 23:14:48 +01:00
class ColProperty {
public static $LEFT = 0;
public static $RIGHT = 1;
public static $CENTER = 2;
2020-11-19 23:15:07 +01:00
public static $COMPLETE = 3;
2020-11-19 23:14:48 +01:00
public static $NORMAL = 0;
public static $HIGH = 1;
public static $WIDE = 2;
public static $WIDEHIGH = 3;
public static $HTML = 0;
public static $PR = 1;
public $length = -1;
private static $freeChars = " ";
public static $LF = 10;
private static $escpos_doubleheight = array(27, 33, 16);
private static $escpos_doublewidth = array(27, 33, 32);
private static $escpos_doubleheightwidth = array(27, 33, 48);
private static $escpos_double_off = array(27, 33, 0);
function __construct($aColSpec) {
if ($aColSpec != "") {
$lengthOfACell = trim($aColSpec);
$this->length = intval($lengthOfACell);
if ($this->length < 0) {
$this->length = 0;
}
}
}
function setLength($len) {
if ($len< 0) {
$this->length = 0;
} else {
$this->length = $len;
}
}
public function render($varcontent,$just,$label,$varstyle,$useColonAfterLabel) {
$endOfLabel = "";
if ($useColonAfterLabel) {
$endOfLabel = ":";
}
if (is_null($varcontent)) {
$text = $label;
} else {
$text = $varcontent;
if ($label != "") {
$text = $label . $endOfLabel . $varcontent;
}
}
$textInCp437 = self::asciiEncodeStringTo437($text);
$contentLength = 0;
$factor = 1;
if (($varstyle == self::$NORMAL) || ($varstyle == self::$HIGH)) {
$contentLength = strlen($textInCp437);
$factor = 1;
} else if ($varstyle == self::$WIDE) {
$contentLength = strlen($textInCp437) * 2;
$factor = 2;
} else if ($varstyle == self::$WIDEHIGH) {
$contentLength = strlen($textInCp437) * 2;
$factor = 2;
}
2020-11-19 23:15:07 +01:00
if ($just == ColProperty::$COMPLETE) {
if ($contentLength > $this->length) {
$textLines = array();
$remaingText = $text;
while (strlen($remaingText) > 0) {
$textToSplit = $remaingText;
$maxLength = strlen($textToSplit) * $factor;
$cutLength = min($maxLength,$this->length / $factor);
$textLines[] = substr($textToSplit,0,$cutLength);
$remaingText = substr($textToSplit,$cutLength);
}
$text = implode("\n", $textLines);
}
return $this->textOutDueToFont(0, $text, 0, $varstyle);
}
2020-11-19 23:14:48 +01:00
$textlen = $contentLength;
if ($contentLength > $this->length) {
$text = substr($text, 0, $this->length / $factor);
$textlen = $this->length;
}
$freeSpace = $this->length - $textlen;
$fillstart = 0;
$fillend = $freeSpace;
if ($just == self::$RIGHT) {
$fillstart = intval($freeSpace);
$fillend = 0;
} else if ($just == self::$CENTER) {
$fillstart = intval($freeSpace / 2);
$fillend = $freeSpace - $fillstart;
}
$out = $this->textOutDueToFont($fillstart, $text, $fillend, $varstyle);
return $out;
}
private function textOutDueToFont($fillspacestart,$text,$fillspaceend,$namestyle) {
$start = substr(self::$freeChars, 0,$fillspacestart);
$end = substr(self::$freeChars, 0,$fillspaceend);
$htmltxt = '';
$fillchar = '';
if (($namestyle == self::$WIDE) || ($namestyle == self::$WIDEHIGH)) {
$fillchar = ' ';
}
for ($i=0;$i<strlen($text);$i++) {
$htmltxt .= $text[$i] . $fillchar;
}
$htmltxt = $start . $htmltxt . $end;
$prbytes = array();
$textInCp437 = self::asciiEncodeStringTo437($text);
$fontctrlstart = array();
$fontctrlend = array();
if ($namestyle == self::$WIDE) {
$fontctrlstart = self::$escpos_doublewidth;
$fontctrlend = self::$escpos_double_off;
} else if ($namestyle == self::$HIGH) {
$fontctrlstart = self::$escpos_doubleheight;
$fontctrlend = self::$escpos_double_off;
} else if ($namestyle == self::$WIDEHIGH) {
$fontctrlstart = self::$escpos_doubleheightwidth;
$fontctrlend = self::$escpos_double_off;
}
for ($i=0;$i<$fillspacestart;$i++) {
$prbytes[] = 32;
}
foreach ($fontctrlstart as $b) {
$prbytes[] = $b;
}
for ($i=0;$i<strlen($textInCp437);$i++) {
//$prbytes[] = $textInCp437[$i];
$prbytes[] = strval(ord(strval($textInCp437[$i])));
}
foreach ($fontctrlend as $b) {
$prbytes[] = $b;
}
for ($i=0;$i<$fillspaceend;$i++) {
$prbytes[] = 32;
}
return array("html" => $htmltxt,"printer" => $prbytes);
}
private static function detect_encoding($string, $enc=null) {
static $list = array('utf-8', 'iso-8859-1', 'windows-1251');
foreach ($list as $item) {
$sample = iconv($item, $item, $string);
if (md5($sample) == md5($string)) {
if ($enc == $item) { return true; } else { return $item; }
}
}
return null;
}
private static function asciiEncodeStringTo437($string)
{
$sourceEncoding = self::detect_encoding($string);
$destinationEncoding = 'CP437'; // Extended ASCII - Codepage 437
$string = iconv($sourceEncoding, $destinationEncoding, $string);
return $string;
}
public function log() {
return "COL(" . $this->length . ")";
}
}
class TemplateTable {
// col properties of each col
private $cols;
// total space for each line
private $totalSpace;
function __construct($tabspecline,$total) {
$this->totalSpace = $total;
// something like TAB:links-3:recht:mittig:5
$this->cols = array();
$colParts = explode(":",$tabspecline);
// remove "TAB"
array_shift($colParts);
foreach($colParts as $aColSpec) {
// "links-4" or "mittig"
$colProperty = new ColProperty($aColSpec);
$this->cols[] = $colProperty;
}
// now check number of elements without length
$colsWithUnSpecifiedLength = 0;
$colsTotalLength = 0;
foreach($this->cols as $aCol) {
if ($aCol->length == -1) {
$colsWithUnSpecifiedLength++;
} else {
$colsTotalLength += $aCol->length;
}
}
$roomToDistribute = $this->totalSpace - $colsTotalLength;
2020-11-19 23:15:07 +01:00
$eachCol = intval($roomToDistribute / max($colsWithUnSpecifiedLength,1));
2020-11-19 23:14:48 +01:00
$assignedCols = 0;
foreach($this->cols as $aCol) {
if ($aCol->length == -1) {
if (($assignedCols+1) == $colsWithUnSpecifiedLength) {
// rest
$aCol->setLength($roomToDistribute - $eachCol * $assignedCols);
} else {
$aCol->setLength($eachCol);
$assignedCols++;
}
}
}
}
public function getColSpec($colNo) {
return $this->cols[$colNo];
}
public function log() {
$log = "";
foreach($this->cols as $aCol) {
$log .= $aCol->log() . " ";
}
return $log;
}
}
class TicketEntry implements JsonSerializable {
private $typeofentry;
private $content;
function __construct($theType,$theContent) {
$this->typeofentry = $theType;
$this->content = $theContent;
}
public function jsonSerialize()
{
$c = $this->content;
if ($this->typeofentry == "bytes") {
$c = implode(',',$this->content);
}
return
[
'typeofentry' => $this->typeofentry,
'content' => $c
];
}
}
class Layouter {
private static $outPr = array();
private static $outHtml = "";
private static $space = 40;
private static $curCol = 0;
private static $tableProperties;
public static function layoutTicket($template,$data,$printersize) {
self::$outPr = array();
self::$outHtml = "";
self::$space = $printersize;
$lines = explode("\n", $template);
self::loop($lines,$data);
2020-11-19 23:15:07 +01:00
if (LAYOUTER_HTML_MODE == 1) {
return array("html" => self::$outHtml, "printer" => self::$outHtml);
} else {
return array("html" => self::$outHtml, "printer" => self::$outPr);
}
2020-11-19 23:14:48 +01:00
}
private static function loop($lines, $data) {
$skippinguntil = null;
foreach ($data as $dataline) {
// iterate through lines- In case of loops the linenumber needs to be incereased inside the loop
$linenumber = 0;
while ($linenumber < count($lines)) {
$t = $lines[$linenumber];
$t = trim($t);
$lineHadContent = false;
if ($t != "") {
$pos = stripos($t,'if:');
if ($pos !== false) {
2020-11-19 23:15:07 +01:00
if (($pos >= 0) && ($pos <= 7)) {
2020-11-19 23:14:48 +01:00
$ifParts = explode(':',$t);
$itemToCheck = $ifParts[1];
$valueToCheck = $ifParts[2];
$realValue = $dataline[$itemToCheck];
if ($realValue != $valueToCheck) {
$skippinguntil = $itemToCheck;
++$linenumber;
continue;
}
}
}
$pos = stripos($t,'fi:');
if ($pos !== false) {
2020-11-19 23:15:07 +01:00
if (($pos >= 0) && ($pos <= 7)) {
2020-11-19 23:14:48 +01:00
$endifParts = explode(':',$t);
$itemToCheck = $endifParts[1];
if ($itemToCheck == $skippinguntil) {
$skippinguntil = null;
++$linenumber;
continue;
}
}
}
if (!is_null($skippinguntil)) {
++$linenumber;
continue;
}
if (CommonUtils::startsWith($t,'#')) {
++$linenumber;
continue;
}
if (CommonUtils::startsWith($t, 'LOGO')) {
$ticketEntry = new TicketEntry("img", "1");
self::$outPr[] = $ticketEntry;
++$linenumber;
continue;
}
2020-11-19 23:15:07 +01:00
$pos = strpos($t,'START');
2020-11-19 23:14:48 +01:00
if ($pos !== false) {
2020-11-19 23:15:07 +01:00
if (($pos >= 0) && ($pos <= 7)) {
2020-11-19 23:14:48 +01:00
$loopDeclParts = explode(':',$t);
$marker = trim($loopDeclParts[1]);
$loopLines = self::collectLinesOfLoop($lines,$linenumber+1,$marker);
$linesToSkip = count($loopLines) + 2;
self::loop($loopLines, $dataline[$marker]);
$linenumber += $linesToSkip;
continue;
}
}
$outContent = array();
$theType = "";
$parts = self::getParts($t);
foreach($parts as $element) {
$elemWithoutBrackets = substr($element, 1, strlen($element)-2);
$partEval = self::evalElem($elemWithoutBrackets,$dataline);
$lineHadContent |= $partEval['linehascontent'];
self::$outHtml .= $partEval["html"];
$theType = $partEval['typeofentry'];
if ($partEval['typeofentry'] == "bytes") {
$outContent = array_merge($outContent,$partEval['bytes']);
} else {
$outContent = $partEval['bytes']; // may be also string for image reference
}
}
if ($lineHadContent) {
$ticketEntry = new TicketEntry($theType, $outContent);
self::$outPr[] = $ticketEntry;
}
} else {
self::$outPr[] = new TicketEntry("bytes",array(ColProperty::$LF));
$lineHadContent = true;
}
if ($lineHadContent) {
self::$outHtml .= "<br>";
self::$curCol = 0;
}
++$linenumber;
}
}
}
private static function collectLinesOfLoop($lines,$linenumber,$marker) {
$looplines = array();
while ($linenumber < count($lines)) {
$aLine = $lines[$linenumber];
$pos = stripos($aLine,'end:'.$marker);
if ($pos !== false) {
if (($pos >= 0) && ($pos < 5)) {
return $looplines;
} else {
$looplines[] = $aLine;
}
} else {
$looplines[] = $aLine;
}
$linenumber++;
}
return $looplines;
}
private static function getCommaSeparatedValuesOfElem($text) {
$out = array();
$parts = explode(":", $text);
if (count($parts) > 1) {
$valsPart = $parts[1];
$out = explode(",",$valsPart);
}
return $out;
}
private static function evalElem($elemContent, $dataline) {
if (self::startsWith($elemContent, "TAB")){
self::setTableProperties($elemContent);
2020-11-19 23:15:07 +01:00
return array("bytes" => array(),"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
2020-11-19 23:14:48 +01:00
} else if (self::startsWith($elemContent, "RAWD")) {
$vals = self::getCommaSeparatedValuesOfElem($elemContent);
return array("bytes" => $vals,"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
} else if (self::startsWith($elemContent, "RAWH")) {
$vals = self::getCommaSeparatedValuesOfElem($elemContent);
$decVals = array();
foreach($vals as $v) {
$decVals[] = hexdec(strtolower($v));
}
return array("bytes" => $decVals,"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
} else if (self::startsWith($elemContent, "LINIE")){
$parts = explode(":", $elemContent);
$charToUse = "-";
if (count($parts) > 1) {
$charToUse = $parts[1];
}
$fillLine = "";
$outbytes = array();
for ($i=0;$i<self::$space;$i++) {
$fillLine .= $charToUse;
$outbytes[] = ord($charToUse);
}
return array("bytes" => $outbytes,"html" => $fillLine, "linehascontent" => true,"typeofentry" => "bytes");
} else if (self::startsWith(strtolower ($elemContent), "qrcode")) {
$qrparts = explode(':', $elemContent);
$scale = 100;
if (count($qrparts) > 1) {
$scale = $qrparts[1];
}
2020-11-19 23:15:07 +01:00
$billid = $dataline["id"];
return array("bytes" => "2,$billid,$scale","html" => "php/contenthandler.php?module=bill&command=billqrcode&billid=$billid", "linehascontent" => true,"typeofentry" => "img");
2020-11-19 23:14:48 +01:00
} else if (self::startsWith(strtolower ($elemContent), "waiterphoto")) {
$parts = explode(':', $elemContent);
$scale = 100;
if (count($parts) > 1) {
$scale = $parts[1];
}
if (isset($dataline["userid"])) {
$userid = $dataline["userid"];
if (!is_null($userid) && (intval($userid) > 0)) {
return array("bytes" => "3,$userid,$scale","html" => "php/contenthandler.php?module=admin&command=getwaiterphotoforprint&userid=$userid", "linehascontent" => true,"typeofentry" => "img");
}
}
} else {
$parts = explode(":", $elemContent);
$placeholder = $parts[0];
$realElem = self::substPlaceholder($placeholder,$dataline);
$lines = explode("\n", $realElem);
if (count($lines) == 1) {
$colContent = self::evalOneElementOfALine($elemContent, $dataline);
} else {
// multiple lines
$colContent = array("html" => "","printer" => array());
$i = 0;
foreach($lines as $contentLine) {
$aDataLine = array($placeholder => $contentLine);
$newColContent = self::evalOneElementOfALine($elemContent, $aDataLine);
if (($i+1) < count($lines)) {
$bytes = array_merge($colContent["printer"],$newColContent["printer"],array(ColProperty::$LF));
$html = $colContent["html"] . $newColContent["html"] . "<br>";
} else {
$bytes = array_merge($colContent["printer"],$newColContent["printer"]);
$html = $colContent["html"] . "<br>" . $newColContent["html"];
}
$colContent = array("html" => $html,"printer" => $bytes);
++$i;
}
}
self::$curCol++;
return array("bytes" => $colContent["printer"],"html" => $colContent["html"], "linehascontent" => true, "typeofentry" => "bytes");
}
}
private static function evalOneElementOfALine($elemContent,$dataline) {
$parts = explode(":", $elemContent);
$placeholder = $parts[0];
$realElem = self::substPlaceholder($placeholder,$dataline);
if (!is_null($realElem) && ($realElem == "")) {
return array("html" => "","printer" => array());
}
$side = ColProperty::$LEFT;
if (count($parts) > 1) {
$just = trim($parts[1]);
if (($just == "links") || ($just == "left")) {
$side = ColProperty::$LEFT;
} else if (($just == "rechts") || ($just == "right")) {
$side = ColProperty::$RIGHT;
} else if (($just == "mittig") || ($just == "center")) {
$side = ColProperty::$CENTER;
2020-11-19 23:15:07 +01:00
} else if (($just == "komplett") || ($just == "complete")) {
$side = ColProperty::$COMPLETE;
2020-11-19 23:14:48 +01:00
}
}
$label = "";
$useColonAfterLabel = true;
if (count($parts) > 2) {
$label = $parts[2];
2020-11-19 23:15:07 +01:00
if (($label != "") && ($label[strlen($label)-1] == " ")) {
2020-11-19 23:14:48 +01:00
$useColonAfterLabel = false;
}
}
$varstyle = ColProperty::$NORMAL;
if (count($parts) > 3) {
switch(trim($parts[3])) {
case "hoch":
$varstyle = ColProperty::$HIGH;
break;
case "breit":
$varstyle = ColProperty::$WIDE;
break;
case "hochbreit":
$varstyle = ColProperty::$WIDEHIGH;
}
}
if (is_null(self::$tableProperties)) {
throw new Exception("TAB-Element fehlt in Vorlage");
}
$colSpec = self::$tableProperties->getColSpec(self::$curCol);
$colContent = $colSpec->render($realElem,$side,$label,$varstyle,$useColonAfterLabel);
return $colContent;
}
private static function substPlaceholder($vartext,$dataline) {
if ($vartext == '-') {
return null;
}
if (isset($dataline[$vartext])) {
return strval($dataline[$vartext]);
} else {
return "";
}
}
private static function getParts($line) {
$matches = null;
preg_match_all('/\{[a-zA-Z0-9éöäüÖÄÜß_\'":\-=\+%\.,\/\(\) ]*\}/', $line, $matches);
return $matches[0];
}
private static function startsWith ($string, $startString)
{
$len = strlen($startString);
return (substr($string, 0, $len) === $startString);
}
private static function addToOut($t) {
if ($t == "\n") {
self::$outHtml .= "<br>";
self::$outPr[] = ColProperty::$LF;
} else {
self::$outHtml .= $t;
self::$outPr .= $t;
}
}
private static function setTableProperties($elem) {
self::$tableProperties = new TemplateTable($elem,self::$space);
self::$curCol = 0;
}
}