mirror of
https://github.com/nzeemin/escparser.git
synced 2025-04-19 17:42:16 +03:00
535 lines
16 KiB
C++
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);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|