1
0
mirror of https://github.com/nzeemin/escparser.git synced 2025-04-19 17:42:16 +03:00
escparser/Interpreter.cpp
2022-11-13 00:07:09 +03:00

535 lines
16 KiB
C++

/* This file is part of UKNCBTL.
UKNCBTL is free software: you can redistribute it and/or modify it under the terms
of the GNU Lesser General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
UKNCBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
UKNCBTL. If not, see <http://www.gnu.org/licenses/>. */
#include "ESCParser.h"
//////////////////////////////////////////////////////////////////////
EscInterpreter::EscInterpreter(std::istream& input, OutputDriver& output) :
m_output(output), m_input(input)
{
m_marginleft = 96; // 96/720 inch = 9.6 points
m_margintop = 160; // 160/720 inch = 16 points
m_endofpage = false;
m_fontsp = m_fontdo = m_fontfe = m_fontks = m_fontel = m_fontun = false;
m_superscript = m_subscript = false;
m_charset = 0;
PrinterReset();
}
unsigned char EscInterpreter::GetNextByte()
{
if (m_input.eof())
return 0;
unsigned char result = (unsigned char) m_input.get();
return result;
}
void EscInterpreter::PrinterReset()
{
m_x = m_y = 0;
m_printmode = false;
//TODO: Íàñòðàèâàòü ðåæèìû ïî DIP-ïåðåêëþ÷àòåëÿì
m_fontsp = m_fontdo = m_fontfe = m_fontks = m_fontel = m_fontun = false;
m_shifty = 720 / 6; // 6 lines/inch
UpdateShiftX();
m_limitright = m_shiftx * 80; //TODO
m_limitbottom = 720 * 11; // 11 inches = 66 lines
m_superscript = m_subscript = false;
m_charset = 0;
}
// Îáíîâèòü çíà÷åíèå m_shiftx â ñîîòâåòñòâèè ñ âûáðàííûì øðèôòîì
void EscInterpreter::UpdateShiftX()
{
m_shiftx = 720 / 10; // Îáû÷íûé èíòåðâàë
if (m_fontel)
m_shiftx = 720 / 12; // Ýëèòà
else if (m_fontks)
m_shiftx = 720 / 17; // Ñæàòûé
if (m_fontsp) // Øðèôò âðàçðÿäêó
m_shiftx *= 2;
}
void EscInterpreter::ShiftY(int shifty)
{
m_y += shifty;
if (m_y >= m_limitbottom) // Proceed to the next page if needed
NextPage();
}
void EscInterpreter::NextPage()
{
m_endofpage = true;
m_x = m_y = 0;
}
// Èíòåðïðåòèðîâàòü ñëåäóþùèé òîêåí
bool EscInterpreter::InterpretNext()
{
if (IsEndOfFile()) return false;
m_endofpage = false;
unsigned char ch = GetNextByte();
if (IsEndOfFile()) return false;
switch (ch)
{
case 0/*NUL*/: case 7/*BEL*/: case 17/*DC1*/: case 19/*DC3*/: case 127/*DEL*/:
break; // Èãíîðèðóåìûå êîäû
case 24/*CAN*/:
NextPage();
return false; //Êîíåö ñòðàíèöû
case 8/*BS*/: // Backspace - ñäâèã íà 1 ñèìâîë íàçàä
m_x -= m_shiftx; if (m_x < 0) m_x = 0;
break;
case 9/*HT*/: // Ãîðèçîíòàëüíàÿ òàáóëÿöèÿ - ðåàëèçîâàí ÷àñòíûé ñëó÷àé
//NOTE: ïåðåóñòàíîâêà ïîçèöèé òàáóëÿöèè èãíîðèðóåòñÿ
m_x += m_shiftx * 8;
m_x = (m_x / (m_shiftx * 8)) * (m_shiftx * 8);
break;
case 10/*LF*/: // Line Feed - ñäâèã ê ñëåäóþùåé ñòðîêå
ShiftY(m_shifty);
return !m_endofpage;
case 11/*VT*/: //Âåðòèêàëüíàÿ òàáóëÿöèÿ - â ÷àñòíîì ñëó÷àå óäîâëåòâîðÿåò îïèñàíèþ.
//NOTE: Ïåðåóñòàíîâêà ïîçèöèé òàáóëÿöèè èãíîðèðóåòñÿ
m_x = 0; ShiftY(m_shifty);
return !m_endofpage;
case 12/*FF*/: // Form Feed - !!! äîäåëàòü
NextPage();
return false;
case 13/*CR*/: // Carriage Return - âîçâðàò êàðåòêè
m_x = 0;
break;
case 14/*SO*/: // Âêëþ÷åíèå øðèôòà âðàçðÿäêó
m_fontsp = true;
UpdateShiftX();
break;
case 15/*SI*/: // Âêëþ÷åíèå ñæàòîãî øðèôòà (17.1 ñèìâîëîâ íà äþéì)
m_fontks = true;
UpdateShiftX();
break;
case 18/*DC2*/: // Âûêëþ÷åíèå ñæàòîãî øðèôòà
m_fontks = false;
UpdateShiftX();
break;
case 20/*DC4*/: // Âûêëþ÷åíèå øðèôòà âðàçðÿäêó
m_fontsp = false;
UpdateShiftX();
break;
case 27/*ESC*/: // Expanded Function Codes
return InterpretEscape();
/* èíà÷å "íàïå÷àòàòü" ñèìâîë */
default:
PrintCharacter(ch);
m_x += m_shiftx;
break;
}
if (m_x >= m_limitright) // Ïðè ïðåâûøåíèè äëèíû ñòðîêè -- àâòîìàòè÷åñêèé ïåðåõîä íà ñëåäóþùóþ
{
m_x = 0;
ShiftY(m_shifty); // Proceed to the next line; probably also to the next page
}
return !m_endofpage;
}
// Èíòåðïðåòèðîâàòü Escape-ïîñëåäîâàòåëüíîñòü
bool EscInterpreter::InterpretEscape()
{
unsigned char ch = GetNextByte();
switch (ch)
{
case 'U': // Ïå÷àòü â îäíîì èëè äâóõ íàïðàâëåíèÿõ
GetNextByte(); // Èãíîðèðóåì
break;
case 'x': // Âûáîð êà÷åñòâà
{
unsigned char ss = GetNextByte();
m_printmode = (ss != 0 && ss != '0');
}
break;
// Ãðóïïà ôóíêöèé character pitch
case 'P': // Âêëþ÷åíèå øðèôòà "ïèêà"
m_fontel = false;
UpdateShiftX();
break;
case 'M': // Âêëþ÷åíèå øðèôòà "ýëèòà" (12 ñèìâîëîâ íà äþéì)
m_fontel = true;
UpdateShiftX();
break;
case 15/*SI*/: // Âêëþ÷åíèå ñæàòîãî øðèôòà
m_fontks = true;
UpdateShiftX();
break;
case '0': // Óñòàíîâêà èíòåðâàëà 1/8"
m_shifty = 720 / 8;
break;
case '1': // Óñòàíîâêà èíòåðâàëà 7/72"
m_shifty = 720 * 7 / 72;
break;
case '2':
m_shifty = 720 / 6; /* set line spacing to 1/6 inch */
break;
case 'A': /* text line spacing */
m_shifty = (720 * (int)GetNextByte() / 60);
break;
case '3': /* graphics line spacing */
m_shifty = (720 * (int)GetNextByte() / 180);
break;
case 'J': /* variable line spacing */
ShiftY((int)GetNextByte() * 720 / 180);
return !m_endofpage;
case 'C': //PageLength - èãíîðèðîâàòü
if (GetNextByte() == 0)
GetNextByte();
break;
case 'N': //Skip perforation - èãíîðèðîâàòü
GetNextByte();
break;
case 'O': break;
case 'B': //Set vertical tabs - èãíîðèðîâàòü ???
while (GetNextByte() != 0);
break;
case '/':
GetNextByte();
break;
case 'D': //Set horizontal tabs - èãíîðèðîâàòü ???
while (GetNextByte() != 0);
break;
case 'Q': //Set right margin - èãíîðèðîâàòü ???
{
int n = (int)GetNextByte();
if (n > 0 && m_shiftx * n <= 720 * 8) // Íå ìåíüøå îäíîãî ñèìâîëà è íå áîëüøå ïîëåçíîé øèðèíû ôîðìàòà (8 äþéìîâ)
m_limitright = m_shiftx * n;
break;
}
case 'K': /* 8-bit single density graphics */
printGR9(12); // 72 / 1.2 = 60
break;
case 'L': /* 8-bit double density graphics */
printGR9(6); // 72 / 0.6 = 120
break;
case 'Y': /* 8-bit double-speed double-density graphics */
printGR9(6, true); // 72 / 0.6 = 120
break;
case 'Z': /* 8-bit quadple-density graphics */
printGR9(3, true); // 72 / 0.3 = 240
break;
case '*': /* Bit Image Graphics Mode */
switch (GetNextByte())
{
case 0: /* same as ESC K, Normal 60 dpi */
printGR9(12); // 72 / 1.2 = 60
break;
case 1: /* same as ESC L, Double 120 dpi */
printGR9(6); // 72 / 0.6 = 120
break;
case 2: /* same as ESC Y, Double speed 120 dpi */
printGR9(6, true); // 72 / 0.6 = 120
break;
case 3: /* same as ESC Z, Quadruple 240 dpi */
printGR9(3, true); // 72 / 0.3 = 240
break;
case 4: /* CRT 1, Semi-double 80 dpi */
printGR9(9); // 72 / 0.9 = 80
break;
case 5: /* Plotter 72 dpi */
printGR9(10); // 72 / 1.0 = 72
break;
case 6: /* CRT 2, 90 dpi */
printGR9(8); // 72 / 0.8 = 90
break;
case 7: /* Double Plotter 144 pdi */
printGR9(5); // 72 / 0.5 = 144
break;
case 32: /* High-resolution for ESC K */
printGR24(2 * 6);
break;
case 33: /* High-resolution for ESC L */
printGR24(6);
break;
case 38: /* CRT 3 */
printGR24(2 * 4);
break;
case 39: /* High-resolution triple-density */
printGR24(2 * 2);
break;
case 40: /* high-resolution hex-density */
printGR24(2);
break;
}
break;
/* reassign bit image command ??? */
case '?': break;
/* download - èãíîðèðîâàòü (???) */
case '&': break; /* this command downloads character sets to the printer */
case '%': break; /* select/deselect download character code */
case ':': /* this command copies the internal character set into the download area */
GetNextByte(); GetNextByte(); GetNextByte();
break;
case 'R': /* international character set - èãíîðèðîâàòü (???) */
m_charset = GetNextByte();
break;
/* MSB control - èãíîðîðèðîâàòü (???) */
case '#': break; /* clear most significant bit */
case '=': break; /* clear most significant bit */
case '>': break; /* set most significant bit */
/* print table control */
case '6': break; /* select upper character set */
case '7': break; /* select lower character set */
/* home head */
case '<':
m_x = 0; /* repositions the print head to the left most column */
break;
case 14/*SO*/: // Âêëþ÷åíèå øðèôòà âðàçðÿäêó
m_fontsp = true;
UpdateShiftX();
break;
/* inter character space */
case 32/*SP*/:
GetNextByte();
break;
/* absolute dot position */
case '$':
m_x = GetNextByte();
m_x += 256 * (int)GetNextByte();
m_x = (int)((int)m_x * 720 / 60);
break;
/* relative dot position */
case '\\':
{
int shift = GetNextByte(); shift += 256 * (int)GetNextByte();
m_x += (int)((int)shift * 720 / (m_printmode ? 180 : 120));
/* !!! ó÷åñòü ìîäó LQ èëè DRAFT */
}
break;
/* CHARACTER CONTROL CODES */
case 'E': // Âêëþ÷åíèå æèðíîãî øðèôòà
m_fontfe = true;
UpdateShiftX();
break;
case 'F': // Âûêëþ÷åíèå æèðíîãî øðèôòà
m_fontfe = false;
UpdateShiftX();
break;
case 'G': // Âêëþ÷åíèå äâîéíîé ïå÷àòè
m_fontdo = true;
break;
case 'H': // Âûêëþ÷åíèå äâîéíîé ïå÷àòè
m_fontdo = false;
m_superscript = m_subscript = false;
break;
case '-': // Ïîä÷åðêèâàíèå
{
unsigned char ss = GetNextByte();
m_fontun = (ss != 0 && ss != '0');
}
break;
case 'S': // Âêëþ÷åíèå ïå÷àòè â âåðõíåé èëè íèæíåé ÷àñòè ñòðîêè
{
unsigned char ss = GetNextByte();
m_superscript = (ss == 0 || ss == '0');
m_subscript = (ss == 1 || ss == '1');
}
break;
case 'T': // Âûêëþ÷åíèå ïå÷àòè â âåðõíåé èëè íèæíåé ÷àñòè ñòðîêè
m_superscript = m_subscript = false;
break;
case 'W': // Âêëþ÷åíèå èëè âûêëþ÷åíèå øðèôòà âðàçðÿäêó
{
unsigned char ss = GetNextByte();
m_fontsp = (ss != 0 && ss != '0');
UpdateShiftX();
}
break;
case '!': // Âûáîð âèäà øðèôòà
{
unsigned char fontbits = GetNextByte();
m_fontel = (fontbits & 1) != 0;
m_fontks = ((fontbits & 4) != 0) && !m_fontel;
m_fontfe = ((fontbits & 8) != 0) && !m_fontel;
m_fontdo = (fontbits & 16) != 0;
m_fontsp = (fontbits & 32) != 0;
UpdateShiftX();
}
break;
/* italic print */
case '4': /* set italics */
break;
case '5': /* clear itelics */
break;
/* character table */
case 't': /* select character table ??? */
GetNextByte(); /* èãíîðèðîâàòü */
break;
/* double height */
case 'w': /* select double height !!! */
GetNextByte();
break;
/* SYSTEM CONTROL CODES */
/* reset */
case '@':
PrinterReset();
break;
/* cut sheet feeder control */
case 25/*EM*/:
GetNextByte(); /* ??? - èãíîðèðîâàòü */
break;
}
return !m_endofpage;
}
void EscInterpreter::printGR9(int dx, bool dblspeed)
{
int width = GetNextByte(); // Êîëè÷åñòâî "êóñî÷êîâ" äàííûõ î èçîáðàæåíèè
width += 256 * (int)GetNextByte();
// ×èòàòü è âûâîäèòü äàííûå
unsigned char lastfbyte = 0;
for (; width > 0; width--)
{
unsigned char fbyte = GetNextByte();
if (dblspeed) //  ðåæèìå âûñîêîé ñêîðîñòè èãíîðèðóåì ïîäðÿä âñòðå÷àþùèåñÿ óäàðû
{
fbyte &= ~lastfbyte;
lastfbyte = fbyte;
}
unsigned char mask = 0x80;
for (int i = 0; i < 8; i++)
{
if (fbyte & mask)
{
DrawStrike(float(m_x), float(m_y + i * 12));
/* 12 ñîîòâåòñòâóåò 1/60 inch... Íà ñàìîì äåëå ðàññòîÿíèå ìåæäó èãëàìè ó
9-pin dot matrix printers = 1/72 inch, íî ïðè ýìóëÿöèè íà 24-pin ïðèíèìàåòñÿ 1/60 */
}
mask >>= 1;
}
m_x += dx;
}
}
void EscInterpreter::printGR24(int dx)
{
int width = GetNextByte(); // Êîëè÷åñòâî "êóñî÷êîâ" äàííûõ î èçîáðàæåíèè
width += 256 * (int)GetNextByte();
// ×èòàòü è âûâîäèòü äàííûå
for (; width > 0; width--)
{
for (unsigned char n = 0; n < 3; n++)
{
unsigned char fbyte = GetNextByte();
unsigned char mask = 0x80;
for (int i = 0; i < 8; i++)
{
if (fbyte & mask)
{
DrawStrike(float(m_x), float((m_y + (n * 4 * 8/*èãë*/) + i * 4)));
/* 4 ñîîòâåòñòâóåò 1/180 inch - ðàññòîÿíèå ìåæäó èãëàìè ó 24-pin dot matrix printers */
}
mask >>= 1;
}
}
m_x += dx;
}
}
void EscInterpreter::PrintCharacter(unsigned char ch)
{
if (ch < 32) return;
if (ch < 160 && ch > 126) return;
// Âû÷èñëÿåì ñèìâîë çíàêîãåíåðàòîðà ïî òåêóùåìó íàáîðó ñèìâîëîâ
int charset = m_charset ^ (ch > 128 ? 1 : 0);
ch &= 0x7f;
int symbol = ch;
if (ch >= (unsigned char)'@' && charset != 0)
symbol += 68;
// Ïîëó÷àåì àäðåñ ñèìâîëà â çíàêîãåíåðàòîðå
const unsigned short* pchardata = RobotronFont + int(symbol - 32) * 9;
float step = float(m_shiftx) / 11.0f; // Øàã ïî ãîðèçîíòàëè
float y = float(m_y);
if (m_subscript) y += 4 * 12;
// Öèêë ïå÷àòè ñèìâîëà ïî ñòðîêàì
unsigned short prevdata = 0;
for (int line = 0; line < 9; line++)
{
unsigned short data = pchardata[line];
// Îñîáàÿ îáðàáîòêà äëÿ íàä- è ïîä-ñòðî÷íûõ ñèìâîëîâ
if ((m_superscript || m_subscript))
{
if ((line & 1) == 0)
{
prevdata = data;
continue;
}
else
{
data |= prevdata; // Îáúåäèíÿåì äâå ñòðîêè ñèìâîëà â îäíó
}
}
for (int col = 0; col < 9; col++) // Öèêë ïå÷àòè òî÷åê ñòðîêè
{
unsigned short bit = (data >> col) & 1;
if (m_fontun && line == 8) bit = 1;
if (!bit) continue;
DrawStrike(m_x + col * step, y);
if (m_fontsp)
DrawStrike(m_x + (col + 1.0f) * step, y);
//TODO: Ó÷èòûâàòü m_fontfe (æèðíûé øðèôò)
}
y += 12; // 12 ñîîòâåòñòâóåò 1/60 inch
}
// Äëÿ m_fontun äîáèâàòü ïîñëåäíþþ òî÷êó
if (m_fontun)
DrawStrike(m_x + 9.0f * step, float(m_y + 8 * 12));
}
void EscInterpreter::DrawStrike(float x, float y)
{
float cx = float(m_marginleft) + x;
float cy = float(m_margintop) + y;
//TODO: Ó÷èòûâàòü m_fontdo â ðàäèóñå òî÷êè
float cr = 6.0f;
m_output.WriteStrike(cx, cy, cr);
}
//////////////////////////////////////////////////////////////////////