openMSX
Printer.cc
Go to the documentation of this file.
1 #include "Printer.hh"
2 #include "PNG.hh"
3 #include "FileOperations.hh"
4 #include "IntegerSetting.hh"
5 #include "MSXMotherBoard.hh"
6 #include "CliComm.hh"
7 #include "MSXException.hh"
8 #include "Math.hh"
9 #include "MemBuffer.hh"
10 #include "serialize.hh"
11 #include "vla.hh"
12 #include "xrange.hh"
13 #include <algorithm>
14 #include <cassert>
15 #include <cmath>
16 #include <cstring>
17 #include <memory>
18 #include <vector>
19 
20 using std::max;
21 using std::min;
22 using std::string;
23 
24 namespace openmsx {
25 
26 class Paper
27 {
28 public:
29  Paper(unsigned x, unsigned y, double dotSizeX, double dotSizeY);
30 
31  [[nodiscard]] std::string save() const;
32  void setDotSize(double sizeX, double sizeY);
33  void plot(double x, double y);
34 
35 private:
36  byte& dot(unsigned x, unsigned y);
37 
38 private:
39  MemBuffer<byte> buf;
40  std::vector<int> table;
41 
42  double radiusX;
43  double radiusY;
44  int radius16;
45 
46  unsigned sizeX;
47  unsigned sizeY;
48 };
49 
50 
51 bool PrinterCore::getStatus(EmuTime::param /*time*/)
52 {
53  return false; // false = low = ready
54 }
55 
56 void PrinterCore::setStrobe(bool strobe, EmuTime::param /*time*/)
57 {
58  if (!strobe && prevStrobe) {
59  // falling edge
60  write(toPrint);
61  }
62  prevStrobe = strobe;
63 }
64 
65 void PrinterCore::writeData(byte data, EmuTime::param /*time*/)
66 {
67  toPrint = data;
68 }
69 
70 void PrinterCore::plugHelper(Connector& /*connector*/, EmuTime::param /*time*/)
71 {
72  // nothing
73 }
74 
75 void PrinterCore::unplugHelper(EmuTime::param /*time*/)
76 {
77  forceFormFeed();
78 }
79 
80 
81 /*
82 // class RawPrinter
83 
84 RawPrinter::RawPrinter()
85 {
86  Properties* properties = propGetGlobalProperties();
87  hFile = CreateFile(properties->ports.Lpt.portName, GENERIC_WRITE,
88  0, nullptr, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, nullptr);
89  if (hFile == INVALID_HANDLE_VALUE) {
90  throw MSXException();
91  }
92 }
93 
94 void RawPrinter::~RawPrinter()
95 {
96  CloseHandle(hFile);
97 }
98 
99 void RawPrinter::write(byte value)
100 {
101  unsigned dwWritten;
102  WriteFile(hFile, &value, 1, &dwWritten, nullptr);
103 }
104 
105 void RawPrinter::forceFormFeed()
106 {
107 }
108 */
109 
110 
111 // class ImagePrinter
112 
113 ImagePrinter::ImagePrinter(MSXMotherBoard& motherBoard_, bool graphicsHiLo_)
114  : motherBoard(motherBoard_)
115  , graphicsHiLo(graphicsHiLo_)
116 {
117  dpiSetting = motherBoard.getSharedStuff<IntegerSetting>(
118  "print-resolution",
119  motherBoard.getCommandController(), "print-resolution",
120  "resolution of the output image of emulated dot matrix printer in DPI",
121  300, 72, 1200);
122 
123  letterQuality = false;
124  bold = false;
125  proportional = false;
126  italic = false;
127  superscript = false;
128  subscript = false;
129  doubleWidth = false;
130  underline = false;
131  doubleStrike = false;
132  escSequence = false;
133  alternateChar = false;
134  detectPaperOut = false;
135  japanese = false;
136  normalAfterLine = false;
137  ninePinGraphics = false;
138  leftToRight = false;
139  elite = false;
140  compressed = false;
141  noHighEscapeCodes = false;
142  eightBit = 0;
143  perforationSkip = 0;
145  sizeEscPos = 0;
147  ramLoadOffset = 0;
148  ramLoadEnd = 0;
150 
151  printAreaTop = -1.0;
152  printAreaBottom = 0.0;
153 }
154 
156 {
158 }
159 
160 void ImagePrinter::write(byte data)
161 {
162  if (ramLoadOffset < ramLoadEnd) {
163  fontInfo.ram[ramLoadOffset++] = data;
164  } else if (sizeRemainingDataBytes) {
165  if (eightBit == 0) {
166  data &= 0x80;
167  } else if (eightBit == 1) {
168  data |= 0x80;
169  }
170  printGraphicByte(data);
172  } else if (escSequence) {
173  escSequence = false;
174 
175  memset(&(abEscSeq), 0, sizeof(abEscSeq));
176  *(abEscSeq) = data;
177  sizeEscPos = 1;
178 
180 
181  if (!remainingCommandBytes) {
183  }
184  } else if (remainingCommandBytes) {
185  abEscSeq[sizeEscPos++] = data;
186 
187  if (!--remainingCommandBytes) {
189  }
190  } else {
191  processCharacter(data);
192  }
193 }
194 
196 {
198 }
199 
201 {
202  resetSettings();
203 
205  hpos = leftBorder;
206  vpos = pageTop;
207 }
208 
209 void ImagePrinter::plot9Dots(double x, double y, unsigned pattern)
210 {
211  for (auto i : xrange(9)) {
212  if (pattern & (1 << i)) {
213  paper->plot(x, y + (8 - i) * pixelSizeY);
214  }
215  }
216 }
217 
219 {
220  ensurePrintPage();
221 
222  double destY = vpos * pixelSizeY;
223  double destHeight = pixelSizeY * 9.0;
224 
225  // Print Data to high 8 bits
226  unsigned charBits = (graphicsHiLo ? Math::reverseByte(data) : data) << 1;
227 
228  printAreaTop = min(printAreaTop, destY);
229  printAreaBottom = max(printAreaBottom, destY + destHeight);
230 
231  // Print bit-mask
232  plot9Dots(hpos * pixelSizeX, destY, charBits);
233 
234  // Move print-position...
236 }
237 
239 {
240  hpos += offset;
241  if (unsigned(hpos) > rightBorder) {
242  hpos = leftBorder;
243  vpos += lineFeed;
244  if (vpos >= pageHeight) {
247  }
248  }
249 }
250 
252 {
253  if (!paper) {
254  // A4 paper format (210mm x 297mm) at 300dpi
255  // TODO make this configurable
256  int dpi = dpiSetting->getInt();
257  auto paperSizeX = unsigned((210 / 25.4) * dpi);
258  auto paperSizeY = unsigned((297 / 25.4) * dpi);
259 
260  auto [dotsX, dotsY] = getNumberOfDots();
261  pixelSizeX = double(paperSizeX) / dotsX;
262  pixelSizeY = double(paperSizeY) / dotsY;
263 
264  paper = std::make_unique<Paper>(paperSizeX, paperSizeY,
266  }
267 }
268 
270 {
271  if (paper) {
273  try {
274  string filename = paper->save();
275  motherBoard.getMSXCliComm().printInfo(
276  "Printed to ", filename);
277  } catch (MSXException& e) {
278  motherBoard.getMSXCliComm().printWarning(
279  "Failed to print: ", e.getMessage());
280  }
281  printAreaTop = -1.0;
282  printAreaBottom = 0.0;
283  }
284  paper.reset();
285  }
286  hpos = leftBorder;
287  vpos = pageTop;
288 }
289 
290 static constexpr unsigned compress9(unsigned a)
291 {
292  unsigned result = 0;
293  for (auto i : xrange(9)) {
294  if (a & (1 << i)) {
295  result |= 1 << (i / 2);
296  }
297  }
298  return result;
299 }
301 {
302  ensurePrintPage();
303 
304  double iYPos = 0;
305  byte* charBitmap = (fontInfo.useRam ? fontInfo.ram : fontInfo.rom)
306  + fontInfo.charWidth * data;
307  byte attribute = charBitmap[0];
308  unsigned start = (attribute >> 4) & 0x07;
309  unsigned end = attribute & 0x0f;
310  unsigned topBits = attribute >> 7;
311  bool script = superscript || subscript;
312 
313  if (!proportional) {
314  start = 0; // Fixed width font
315  end = fontInfo.charWidth - 1;
316  }
317  if (subscript) {
318  iYPos /= 2.0;
319  iYPos += pixelSizeY * 4.5;
320  }
321  if (script) {
322  iYPos -= pixelSizeY * 4.5;
323  }
324 
325  double hPos = hpos;
326  double headRelative = (doubleWidth ? 2 : 1) * fontInfo.pixelDelta / fontDensity;
327 
328  double destY = vpos * pixelSizeY + iYPos;
329  double destHeight = pixelSizeY * 9.0;
330  double dblStrikeOffset = doubleStrike ? (pixelSizeY / 2.5) : 0.0;
331  printAreaTop = min(printAreaTop, destY);
332  printAreaBottom = max(printAreaBottom, destY + destHeight + dblStrikeOffset);
333 
334  for (auto i : xrange(start, end)) {
335  unsigned charBits = unsigned(charBitmap[i + 1]) << topBits;
336 
337  if (underline) {
338  charBits |= 2;
339  }
340  if (script) {
341  charBits = compress9(charBits);
342  }
343 
344  for (auto d : xrange(doubleWidth ? 2 : 1)) {
345  for (auto b : xrange(bold ? 2 : 1)) {
346  for (auto y : xrange(doubleStrike ? 2: 1)) {
347  double destX = (hPos + (d + b / 2.0) / fontDensity) * pixelSizeX;
348  plot9Dots(destX, destY + y * dblStrikeOffset, charBits);
349  }
350  }
351  }
352  hPos += headRelative;
353  }
354  seekPrinterHeadRelative((1 + end - start) * headRelative);
355 }
356 
357 
358 // class ImagePrinterMSX
359 
360 // MSX-Font taken from NMS8250 BIOS ROM
361 constexpr byte MSXFontRaw[256 * 8] = {
362  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
363  0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C, // 1
364  0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x66, 0x3C, // 2
365  0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, // 3
366  0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, // 4
367  0x10, 0x38, 0x54, 0xFE, 0x54, 0x10, 0x38, 0x00, // 5
368  0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x10, 0x38, 0x00, // 6
369  0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, // 7
370  0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, // 8
371  0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, // 9
372  0xC7, 0xBB, 0x7D, 0x7D, 0x7D, 0xBB, 0xC7, 0xFF, // 10
373  0x0F, 0x03, 0x05, 0x79, 0x88, 0x88, 0x88, 0x70, // 11
374  0x38, 0x44, 0x44, 0x44, 0x38, 0x10, 0x7C, 0x10, // 12
375  0x30, 0x28, 0x24, 0x24, 0x28, 0x20, 0xE0, 0xC0, // 13
376  0x3C, 0x24, 0x3C, 0x24, 0x24, 0xE4, 0xDC, 0x18, // 14
377  0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 15
378  0x10, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x10, 0x10, // 16
379  0x10, 0x10, 0x10, 0xFF, 0x00, 0x00, 0x00, 0x00, // 17
380  0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, 0x10, // 18
381  0x10, 0x10, 0x10, 0xF0, 0x10, 0x10, 0x10, 0x10, // 19
382  0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, // 20
383  0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, // 21
384  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 22
385  0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, // 23
386  0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, // 24
387  0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x10, 0x10, // 25
388  0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, // 26
389  0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, // 27
390  0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, // 28
391  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, // 29
392  0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, // 30
393  0x00, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x00, 0x00, // 31
394  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32
395  0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20, 0x00, // 33
396  0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // 34
397  0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, // 35
398  0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00, // 36
399  0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18, 0x00, // 37
400  0x40, 0xA0, 0x40, 0xA8, 0x90, 0x98, 0x60, 0x00, // 38
401  0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // 39
402  0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, // 40
403  0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00, // 41
404  0x20, 0xA8, 0x70, 0x20, 0x70, 0xA8, 0x20, 0x00, // 42
405  0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, // 43
406  0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, // 44
407  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, // 45
408  0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, // 46
409  0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, // 47
410  0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70, 0x00, // 48
411  0x20, 0x60, 0xA0, 0x20, 0x20, 0x20, 0xF8, 0x00, // 49
412  0x70, 0x88, 0x08, 0x10, 0x60, 0x80, 0xF8, 0x00, // 50
413  0x70, 0x88, 0x08, 0x30, 0x08, 0x88, 0x70, 0x00, // 51
414  0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00, // 52
415  0xF8, 0x80, 0xE0, 0x10, 0x08, 0x10, 0xE0, 0x00, // 53
416  0x30, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70, 0x00, // 54
417  0xF8, 0x88, 0x10, 0x20, 0x20, 0x20, 0x20, 0x00, // 55
418  0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, // 56
419  0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0x60, 0x00, // 57
420  0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, // 58
421  0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x40, // 59
422  0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, // 60
423  0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, // 61
424  0xC0, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC0, 0x00, // 62
425  0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00, // 63
426  0x70, 0x88, 0x08, 0x68, 0xA8, 0xA8, 0x70, 0x00, // 64
427  0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, // 65
428  0xF0, 0x48, 0x48, 0x70, 0x48, 0x48, 0xF0, 0x00, // 66
429  0x30, 0x48, 0x80, 0x80, 0x80, 0x48, 0x30, 0x00, // 67
430  0xE0, 0x50, 0x48, 0x48, 0x48, 0x50, 0xE0, 0x00, // 68
431  0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, // 69
432  0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, // 70
433  0x70, 0x88, 0x80, 0xB8, 0x88, 0x88, 0x70, 0x00, // 71
434  0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, // 72
435  0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, // 73
436  0x38, 0x10, 0x10, 0x10, 0x90, 0x90, 0x60, 0x00, // 74
437  0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, // 75
438  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, // 76
439  0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88, 0x00, // 77
440  0x88, 0xC8, 0xC8, 0xA8, 0x98, 0x98, 0x88, 0x00, // 78
441  0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 79
442  0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, // 80
443  0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68, 0x00, // 81
444  0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00, // 82
445  0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00, // 83
446  0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, // 84
447  0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 85
448  0x88, 0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, // 86
449  0x88, 0x88, 0x88, 0xA8, 0xA8, 0xD8, 0x88, 0x00, // 87
450  0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, // 88
451  0x88, 0x88, 0x88, 0x70, 0x20, 0x20, 0x20, 0x00, // 89
452  0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, // 90
453  0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x00, // 91
454  0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, // 92
455  0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, // 93
456  0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, // 94
457  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, // 95
458  0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 96
459  0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 97
460  0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00, // 98
461  0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, // 99
462  0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00, // 100
463  0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 101
464  0x10, 0x28, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x00, // 102
465  0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x70, // 103
466  0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x88, 0x00, // 104
467  0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, // 105
468  0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x90, 0x60, // 106
469  0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, // 107
470  0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, // 108
471  0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00, // 109
472  0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, // 110
473  0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, // 111
474  0x00, 0x00, 0xB0, 0xC8, 0xC8, 0xB0, 0x80, 0x80, // 112
475  0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x08, // 113
476  0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00, // 114
477  0x00, 0x00, 0x78, 0x80, 0xF0, 0x08, 0xF0, 0x00, // 115
478  0x40, 0x40, 0xF0, 0x40, 0x40, 0x48, 0x30, 0x00, // 116
479  0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x68, 0x00, // 117
480  0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, // 118
481  0x00, 0x00, 0x88, 0xA8, 0xA8, 0xA8, 0x50, 0x00, // 119
482  0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, // 120
483  0x00, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x70, // 121
484  0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, // 122
485  0x18, 0x20, 0x20, 0x40, 0x20, 0x20, 0x18, 0x00, // 123
486  0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00, // 124
487  0xC0, 0x20, 0x20, 0x10, 0x20, 0x20, 0xC0, 0x00, // 125
488  0x40, 0xA8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 126
489  0x00, 0x00, 0x20, 0x50, 0xF8, 0x00, 0x00, 0x00, // 127
490  0x70, 0x88, 0x80, 0x80, 0x88, 0x70, 0x20, 0x60, // 128
491  0x90, 0x00, 0x00, 0x90, 0x90, 0x90, 0x68, 0x00, // 129
492  0x10, 0x20, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 130
493  0x20, 0x50, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 131
494  0x48, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 132
495  0x20, 0x10, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 133
496  0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 134
497  0x00, 0x70, 0x80, 0x80, 0x80, 0x70, 0x10, 0x60, // 135
498  0x20, 0x50, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 136
499  0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 137
500  0x20, 0x10, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 138
501  0x50, 0x00, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 139
502  0x20, 0x50, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 140
503  0x40, 0x20, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 141
504  0x50, 0x00, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 142
505  0x20, 0x00, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 143
506  0x10, 0x20, 0xF8, 0x80, 0xF0, 0x80, 0xF8, 0x00, // 144
507  0x00, 0x00, 0x6C, 0x12, 0x7E, 0x90, 0x6E, 0x00, // 145
508  0x3E, 0x50, 0x90, 0x9C, 0xF0, 0x90, 0x9E, 0x00, // 146
509  0x60, 0x90, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 147
510  0x90, 0x00, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 148
511  0x40, 0x20, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 149
512  0x40, 0xA0, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 150
513  0x40, 0x20, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 151
514  0x90, 0x00, 0x90, 0x90, 0xB0, 0x50, 0x10, 0xE0, // 152
515  0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, // 153
516  0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 154
517  0x20, 0x20, 0x78, 0x80, 0x80, 0x78, 0x20, 0x20, // 155
518  0x18, 0x24, 0x20, 0xF8, 0x20, 0xE2, 0x5C, 0x00, // 156
519  0x88, 0x50, 0x20, 0xF8, 0x20, 0xF8, 0x20, 0x00, // 157
520  0xC0, 0xA0, 0xA0, 0xC8, 0x9C, 0x88, 0x88, 0x8C, // 158
521  0x18, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x40, // 159
522  0x10, 0x20, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 160
523  0x10, 0x20, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 161
524  0x20, 0x40, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 162
525  0x20, 0x40, 0x00, 0x90, 0x90, 0x90, 0x68, 0x00, // 163
526  0x50, 0xA0, 0x00, 0xA0, 0xD0, 0x90, 0x90, 0x00, // 164
527  0x28, 0x50, 0x00, 0xC8, 0xA8, 0x98, 0x88, 0x00, // 165
528  0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0xF8, // 166
529  0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00, 0xF0, // 167
530  0x20, 0x00, 0x20, 0x40, 0x80, 0x88, 0x70, 0x00, // 168
531  0x00, 0x00, 0x00, 0xF8, 0x80, 0x80, 0x00, 0x00, // 169
532  0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x00, 0x00, // 170
533  0x84, 0x88, 0x90, 0xA8, 0x54, 0x84, 0x08, 0x1C, // 171
534  0x84, 0x88, 0x90, 0xA8, 0x58, 0xA8, 0x3C, 0x08, // 172
535  0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, // 173
536  0x00, 0x00, 0x24, 0x48, 0x90, 0x48, 0x24, 0x00, // 174
537  0x00, 0x00, 0x90, 0x48, 0x24, 0x48, 0x90, 0x00, // 175
538  0x28, 0x50, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 176
539  0x28, 0x50, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 177
540  0x28, 0x50, 0x00, 0x70, 0x20, 0x20, 0x70, 0x00, // 178
541  0x28, 0x50, 0x00, 0x20, 0x20, 0x20, 0x70, 0x00, // 179
542  0x28, 0x50, 0x00, 0x70, 0x88, 0x88, 0x70, 0x00, // 180
543  0x50, 0xA0, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 181
544  0x28, 0x50, 0x00, 0x88, 0x88, 0x88, 0x70, 0x00, // 182
545  0x50, 0xA0, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 183
546  0xFC, 0x48, 0x48, 0x48, 0xE8, 0x08, 0x50, 0x20, // 184
547  0x00, 0x50, 0x00, 0x50, 0x50, 0x50, 0x10, 0x20, // 185
548  0xC0, 0x44, 0xC8, 0x54, 0xEC, 0x54, 0x9E, 0x04, // 186
549  0x10, 0xA8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // 187
550  0x00, 0x20, 0x50, 0x88, 0x50, 0x20, 0x00, 0x00, // 188
551  0x88, 0x10, 0x20, 0x40, 0x80, 0x28, 0x00, 0x00, // 189
552  0x7C, 0xA8, 0xA8, 0x68, 0x28, 0x28, 0x28, 0x00, // 190
553  0x38, 0x40, 0x30, 0x48, 0x48, 0x30, 0x08, 0x70, // 191
554  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 192
555  0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 193
556  0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 194
557  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 195
558  0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, // 196
559  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, // 197
560  0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 198
561  0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // 199
562  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // 200
563  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 201
564  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 202
565  0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 203
566  0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 204
567  0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, // 205
568  0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, // 206
569  0x80, 0xC0, 0xE0, 0xF0, 0xE0, 0xC0, 0x80, 0x00, // 207
570  0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, // 208
571  0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x3C, 0x7E, 0xFF, // 209
572  0x81, 0xC3, 0xE7, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, // 210
573  0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 211
574  0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 212
575  0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 213
576  0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 214
577  0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 215
578  0x00, 0x20, 0x20, 0x50, 0x50, 0x88, 0xF8, 0x00, // 216
579  0x20, 0x20, 0x70, 0x20, 0x70, 0x20, 0x20, 0x00, // 217
580  0x00, 0x00, 0x00, 0x50, 0x88, 0xA8, 0x50, 0x00, // 218
581  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 219
582  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 220
583  0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 221
584  0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 222
585  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 223
586  0x00, 0x00, 0x68, 0x90, 0x90, 0x90, 0x68, 0x00, // 224
587  0x30, 0x48, 0x48, 0x70, 0x48, 0x48, 0x70, 0xC0, // 225
588  0xF8, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, // 226
589  0xF8, 0x50, 0x50, 0x50, 0x50, 0x50, 0x98, 0x00, // 227
590  0xF8, 0x88, 0x40, 0x20, 0x40, 0x88, 0xF8, 0x00, // 228
591  0x00, 0x00, 0x78, 0x90, 0x90, 0x90, 0x60, 0x00, // 229
592  0x00, 0x50, 0x50, 0x50, 0x50, 0x68, 0x80, 0x80, // 230
593  0x00, 0x50, 0xA0, 0x20, 0x20, 0x20, 0x20, 0x00, // 231
594  0xF8, 0x20, 0x70, 0xA8, 0xA8, 0x70, 0x20, 0xF8, // 232
595  0x20, 0x50, 0x88, 0xF8, 0x88, 0x50, 0x20, 0x00, // 233
596  0x70, 0x88, 0x88, 0x88, 0x50, 0x50, 0xD8, 0x00, // 234
597  0x30, 0x40, 0x40, 0x20, 0x50, 0x50, 0x50, 0x20, // 235
598  0x00, 0x00, 0x00, 0x50, 0xA8, 0xA8, 0x50, 0x00, // 236
599  0x08, 0x70, 0xA8, 0xA8, 0xA8, 0x70, 0x80, 0x00, // 237
600  0x38, 0x40, 0x80, 0xF8, 0x80, 0x40, 0x38, 0x00, // 238
601  0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, // 239
602  0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, // 240
603  0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0xF8, 0x00, // 241
604  0xC0, 0x30, 0x08, 0x30, 0xC0, 0x00, 0xF8, 0x00, // 242
605  0x18, 0x60, 0x80, 0x60, 0x18, 0x00, 0xF8, 0x00, // 243
606  0x10, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // 244
607  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA0, 0x40, // 245
608  0x00, 0x20, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x00, // 246
609  0x00, 0x50, 0xA0, 0x00, 0x50, 0xA0, 0x00, 0x00, // 247
610  0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, // 248
611  0x00, 0x30, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, // 249
612  0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, // 250
613  0x3E, 0x20, 0x20, 0x20, 0xA0, 0x60, 0x20, 0x00, // 251
614  0xA0, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, // 252
615  0x40, 0xA0, 0x20, 0x40, 0xE0, 0x00, 0x00, 0x00, // 253
616  0x00, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, // 254
617  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 255
618 };
619 
620 static byte MSXFont[256 * 9];
621 
623  : ImagePrinter(motherBoard_, true)
624 {
625  msxPrnSetFont(MSXFontRaw);
627 }
628 
629 std::string_view ImagePrinterMSX::getName() const
630 {
631  return "msx-printer";
632 }
633 
634 std::string_view ImagePrinterMSX::getDescription() const
635 {
636  // TODO which printer type
637  return "Emulate MSX printer, prints to image.";
638 }
639 
640 void ImagePrinterMSX::msxPrnSetFont(const byte* msxBits)
641 {
642  // Convert MSX printer font to Epson printer font
643  for (auto i : xrange(256)) {
644  byte oneBits = 0;
645  int start = -1;
646  int end = 0;
647 
648  // Rotate MSX character
649  for (auto j : xrange(8)) {
650  byte charBits = 0;
651  for (auto k : xrange(8)) {
652  charBits |= ((msxBits[8 * i + 7 - k] >> (7 - j)) & 1) << k;
653  }
654 
655  oneBits |= charBits;
656  if (oneBits != 0 && start < 0) start = j;
657  if (charBits != 0) end = j;
658  MSXFont[9 * i + j + 1] = charBits;
659  }
660 
661  end = end + 1;
662  if (start < 0 || start >= 7) start = 0;
663  if (end == 1) end = 5;
664  if (end >= 7) end = 7;
665  MSXFont[9 * i] = (start << 4) | end;
666  }
667 }
668 
669 std::pair<unsigned, unsigned> ImagePrinterMSX::getNumberOfDots()
670 {
671  return {825, 825};
672 }
673 
674 void ImagePrinterMSX::resetSettings()
675 {
676  lineFeed = 12.0;
677  leftBorder = 48;
678  rightBorder = 800;
679  graphDensity = 1.0;
680  fontDensity = 1.0;
681  pageTop = 48;
682  lines = 72;
683  fontWidth = 8;
684  eightBit = -1;
685 
686  // note: this only overwrites 9/12 of the fontInfo.rom array.
687  memcpy(fontInfo.rom, MSXFont, sizeof(MSXFont));
688  fontInfo.charWidth = 9;
689  fontInfo.pixelDelta = 1.0;
690  fontInfo.useRam = false;
691 }
692 
693 
694 unsigned ImagePrinterMSX::calcEscSequenceLength(byte character)
695 {
696  switch (character) {
697  case 'C':
698  return 1;
699  case 'T': case 'Z':
700  return 2;
701  case 'O': case '\\': case 'L': case '/':
702  return 3;
703  case 'S':
704  return 4;
705  case 'G':
706  return 7;
707  default:
708  return 0;
709  }
710 }
711 
712 unsigned ImagePrinterMSX::parseNumber(unsigned sizeStart, unsigned sizeChars)
713 {
714  unsigned Value = 0;
715  while (sizeChars--) {
716  Value = Value * 10;
717  byte data = abEscSeq[sizeStart++];
718  if (data >= '0' && data <= '9') {
719  Value += unsigned(data - '0');
720  }
721  }
722  return Value;
723 }
724 
725 void ImagePrinterMSX::processEscSequence()
726 {
727  switch (abEscSeq[0]) {
728  case 'N':
729  proportional = false;
730  fontDensity = 1.0;
731  break;
732  case 'E':
733  proportional = false;
734  fontDensity = 1.40;
735  break;
736  case 'Q':
737  proportional = false;
738  fontDensity = 1.72;
739  break;
740  case 'P':
741  proportional = true;
742  fontDensity = 0.90;
743  break;
744  case '!':
745  letterQuality = true;
746  break;
747  case '\"':
748  letterQuality = false;
749  break;
750  case 'C':
751  switch (abEscSeq[1]) {
752  case 'D':
753  doubleStrike = true;
754  break;
755  case 'd':
756  doubleStrike = false;
757  break;
758  case 'I':
759  italic = true;
760  break;
761  case 'i':
762  italic = false;
763  break;
764  case 'B':
765  bold = true;
766  break;
767  case 'b':
768  bold = false;
769  break;
770  case 'S':
771  superscript = true;
772  break;
773  case 's':
774  superscript = false;
775  break;
776  case 'U':
777  subscript = true;
778  break;
779  case 'u':
780  subscript = false;
781  break;
782  }
783  break;
784  case '(': // ???: Set a horizontal tab position
785  break;
786  case ')': // ???: Partially delete a horizontal tab position
787  break;
788  case '2': // ???: Clear horizontal tabs
789  break;
790  case 'O':
791  switch (abEscSeq[1]) {
792  case 'S':
793  perforationSkip = parseNumber(2, 2);
794  break;
795  case 'I': // ???: Set page-height(inches)
796  break;
797  default: // ???: Set page-height (lines)
798  break;
799  }
800  break;
801  case '/': // Right margin
802  break;
803  case 'L':
804  leftBorder = parseNumber(1, 3);
805  break;
806  case 'A': // ???: Line-feed 1/6"
807  lineFeed = 12.0;
808  break;
809  case 'B': // ???: Line-feed 1/9"
810  lineFeed = 8.0;
811  break;
812  case 'T': // ???: Line-feed nn/144"
813  lineFeed = parseNumber(1, 2) / 2.0;
814  break;
815  case 'Z': // ???: Line-feed nn/216"
816  lineFeed = parseNumber(1, 2) / 3.0;
817  break;
818  case '[': // ???: Uni-directional printing
819  break;
820  case ']': // ???: Bi-directional printing
821  break;
822  case 'p':
823  detectPaperOut = true;
824  break;
825  case 'q':
826  detectPaperOut = false;
827  break;
828  case 13: // (ESC, CR) Move printer-head to end-position
829  break;
830  case '@':
832  break;
833  case '\\':
834  rightBorder = parseNumber(1, 3);
835  break;
836  case 'G':
837  graphDensity = parseNumber(1, 3) / 100.0;
838  if (graphDensity < 0.1) {
839  graphDensity = 0.1;
840  }
841  sizeRemainingDataBytes = parseNumber(4, 4);
842  break;
843  case 'S': // Print graphics, density depending on font
844  sizeRemainingDataBytes = parseNumber(1, 4);
845  break;
846  case 'X':
847  underline = true;
848  break;
849  case 'Y':
850  underline = false;
851  break;
852  case '&':
853  case '$':
854  japanese = !japanese;
855  break;
856  case 'f': // ???: Scroll paper forward
857  break;
858  case 'r': // ???: Scroll paper back
859  break;
860  }
861 }
862 
863 void ImagePrinterMSX::processCharacter(byte data)
864 {
865  if (alternateChar) {
866  // Print SOH-preceded character
867  printVisibleCharacter(data & 0x1F);
868  alternateChar = false;
869  } else {
870  switch (data) {
871  case 1: // SOH: A symbolcode preceding code
872  alternateChar = true;
873  break;
874  case 7: // BEL: Audible beep (buzzer, 0.3s)
875  break;
876  case 8: // BS: Backstep (1 Character)
877  // TODO: fix for other font-sizes
878  hpos -= 8;
879  if (hpos < leftBorder) {
880  hpos = leftBorder;
881  }
882  break;
883  case 9: // HAT: Horizontal tabulator
884  // TODO: fix for other font-sizes
885  hpos = ((unsigned(hpos) + 64 - leftBorder) & ~63)
886  + leftBorder;
887  if (hpos < rightBorder) {
888  break;
889  }
890  hpos = leftBorder;
891  [[fallthrough]];
892  case 10: // LF: Carriage return + Line feed
893  case 11: // VT: Vertical tabulator (like LF)
894  //hpos = leftBorder;
895  vpos += lineFeed;
896  if (vpos >= pageHeight) {
898  }
899  break;
900  case 12: // FF: Form feed
901  ensurePrintPage();
903  break;
904  case 13: // CR: Carriage return
905  hpos = leftBorder;
906  break;
907  case 14: // SO: Double character-width on
908  doubleWidth = true;
909  break;
910  case 15: // SI: Double character-width off
911  doubleWidth = false;
912  break;
913  case 27:
914  escSequence = true;
915  break;
916  default:
917  if (data >= 32) {
918  // Yes, we can print it!
919  printVisibleCharacter(data);
920  }
921  break;
922  }
923  }
924 }
925 
926 template<typename Archive>
927 void ImagePrinterMSX::serialize(Archive& /*ar*/, unsigned /*version*/)
928 {
929  // TODO is this worth it?
930 }
933 
934 
935 // class ImagePrinterEpson
936 
937 constexpr byte EpsonFontRom[] = {
938  0x8b, 0x04, 0x0a, 0x20, 0x8a, 0x60, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 0
939  0x8b, 0x1c, 0x22, 0x08, 0xa2, 0x48, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 1
940  0x9b, 0x00, 0x3c, 0x00, 0x82, 0x40, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 2
941  0x9a, 0x00, 0x1c, 0x22, 0x80, 0x62, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 3
942  0x96, 0x00, 0x12, 0x80, 0x5e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 4
943  0xa7, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 5
944  0x8b, 0x12, 0x00, 0x7e, 0x80, 0x12, 0x80, 0x02, 0x80, 0x42, 0x00, 0x00, // 6
945  0xc8, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7
946  0x8b, 0x06, 0x00, 0x09, 0x00, 0x51, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // 8
947  0x8b, 0x5e, 0x80, 0x10, 0x80, 0x08, 0x40, 0x04, 0x40, 0x9e, 0x00, 0x00, // 9
948  0x8a, 0x40, 0x9e, 0x00, 0x90, 0x40, 0x10, 0x4e, 0x80, 0x00, 0x00, 0x00, // 10
949  0x8b, 0x92, 0x28, 0x44, 0x00, 0x44, 0x00, 0x44, 0x28, 0x92, 0x00, 0x00, // 11
950  0x8b, 0xfe, 0x00, 0xa0, 0x00, 0x48, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x00, // 12
951  0x8b, 0x06, 0x08, 0x54, 0xa0, 0x04, 0xa0, 0x54, 0x08, 0x06, 0x00, 0x00, // 13
952  0x8b, 0x04, 0x0a, 0x20, 0x0a, 0xa0, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 14
953  0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x46, 0x00, 0x44, 0x00, 0x00, 0x00, // 15
954  0x9a, 0x00, 0x50, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x14, 0x00, 0x00, 0x00, // 16
955  0x8a, 0x7e, 0x80, 0x00, 0x80, 0x12, 0x80, 0x12, 0x6c, 0x00, 0x00, 0x00, // 17
956  0x8b, 0x3e, 0x40, 0x90, 0x00, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x00, // 18
957  0x8b, 0x2c, 0x02, 0x28, 0x02, 0x1c, 0x20, 0x0a, 0x20, 0x1a, 0x00, 0x00, // 19
958  0x8b, 0x3a, 0x44, 0x00, 0x8a, 0x10, 0xa2, 0x00, 0x44, 0xb8, 0x00, 0x00, // 20
959  0x8b, 0x02, 0x08, 0x14, 0x22, 0x08, 0x22, 0x14, 0x08, 0x20, 0x00, 0x00, // 21
960  0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 22
961  0x8b, 0x06, 0x88, 0x14, 0x20, 0x44, 0x20, 0x14, 0x88, 0x06, 0x00, 0x00, // 23
962  0x8b, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, // 24
963  0x8b, 0x3c, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x82, 0x3c, 0x00, 0x00, // 25
964  0x8b, 0x04, 0x0a, 0xa0, 0x0a, 0x20, 0x0a, 0xa0, 0x1c, 0x02, 0x00, 0x00, // 26
965  0x9a, 0x00, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, 0x00, // 27
966  0x8a, 0x3c, 0x80, 0x02, 0x00, 0x02, 0x80, 0x3c, 0x02, 0x00, 0x00, 0x00, // 28
967  0x8b, 0x3e, 0x00, 0x2a, 0x00, 0x6a, 0x80, 0x2a, 0x00, 0x22, 0x00, 0x00, // 29
968  0x8b, 0x1c, 0x22, 0x08, 0x22, 0x48, 0xa2, 0x08, 0x22, 0x18, 0x00, 0x00, // 30
969  0x8b, 0xa8, 0x00, 0x68, 0x00, 0x3e, 0x00, 0x68, 0x00, 0xa8, 0x00, 0x00, // 31
970  0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32
971  0xc8, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 33
972  0xa9, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, // 34
973  0x8b, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0x00, // 35
974  0x8b, 0x24, 0x00, 0x54, 0x00, 0xfe, 0x00, 0x54, 0x00, 0x48, 0x00, 0x00, // 36
975  0x8b, 0xc0, 0x02, 0xc4, 0x08, 0x10, 0x20, 0x46, 0x80, 0x06, 0x00, 0x00, // 37
976  0x8b, 0x4c, 0xa0, 0x12, 0xa0, 0x4a, 0x00, 0x04, 0x08, 0x12, 0x00, 0x00, // 38
977  0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 39
978  0xc9, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, // 40
979  0xa7, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 41
980  0x8b, 0x10, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x10, 0x00, 0x00, // 42
981  0x8b, 0x10, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 43
982  0x39, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, // 44
983  0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 45
984  0xa8, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 46
985  0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 47
986  0x8b, 0x38, 0x44, 0x00, 0x82, 0x00, 0x82, 0x00, 0x44, 0x38, 0x00, 0x00, // 48
987  0xa9, 0x00, 0x00, 0x42, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // 49
988  0x8b, 0x42, 0x80, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x62, 0x00, 0x00, // 50
989  0x8b, 0x84, 0x00, 0x82, 0x00, 0xa2, 0x00, 0xd2, 0x00, 0x8c, 0x00, 0x00, // 51
990  0x8b, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x00, // 52
991  0x8b, 0xe4, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x9c, 0x00, 0x00, // 53
992  0x8b, 0x0c, 0x12, 0x20, 0x52, 0x80, 0x12, 0x00, 0x12, 0x0c, 0x00, 0x00, // 54
993  0x8b, 0x80, 0x00, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x80, 0x00, 0x00, // 55
994  0x8b, 0x6c, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x6c, 0x00, 0x00, // 56
995  0x8b, 0x60, 0x90, 0x00, 0x90, 0x02, 0x94, 0x08, 0x90, 0x60, 0x00, 0x00, // 57
996  0xa7, 0x00, 0x00, 0x36, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58
997  0x27, 0x00, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 59
998  0x89, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 60
999  0x8b, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, // 61
1000  0xab, 0x00, 0x00, 0x82, 0x00, 0x44, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, // 62
1001  0x8b, 0x40, 0x80, 0x00, 0x80, 0x0a, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, // 63
1002  0x8b, 0x38, 0x44, 0x82, 0x10, 0xaa, 0x00, 0xaa, 0x00, 0x7a, 0x00, 0x00, // 64
1003  0x8b, 0x1e, 0x20, 0x48, 0x80, 0x08, 0x80, 0x48, 0x20, 0x1e, 0x00, 0x00, // 65
1004  0x8b, 0x82, 0x7c, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x6c, 0x00, 0x00, // 66
1005  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x00, 0x00, // 67
1006  0x8b, 0x82, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, // 68
1007  0x8b, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x82, 0x00, 0x00, // 69
1008  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x80, 0x00, 0x00, // 70
1009  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x10, 0x82, 0x10, 0x82, 0x5c, 0x00, 0x00, // 71
1010  0x8b, 0xfe, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x00, // 72
1011  0xa9, 0x00, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 73
1012  0x8a, 0x0c, 0x02, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x80, 0x00, 0x00, 0x00, // 74
1013  0x8b, 0xfe, 0x00, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, // 75
1014  0x8b, 0xfe, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, // 76
1015  0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x20, 0x40, 0x00, 0xfe, 0x00, 0x00, // 77
1016  0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0xfe, 0x00, 0x00, // 78
1017  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x00, 0x00, // 79
1018  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x60, 0x00, 0x00, // 80
1019  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x08, 0x82, 0x04, 0x80, 0x7a, 0x00, 0x00, // 81
1020  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x98, 0x04, 0x62, 0x00, 0x00, // 82
1021  0x8b, 0x64, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x4c, 0x00, 0x00, // 83
1022  0x8b, 0x80, 0x00, 0x80, 0x00, 0xfe, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 84
1023  0x8b, 0xfc, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xfc, 0x00, 0x00, // 85
1024  0x8b, 0xe0, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0xe0, 0x00, 0x00, // 86
1025  0x8b, 0xfc, 0x02, 0x04, 0x08, 0x30, 0x08, 0x04, 0x02, 0xfc, 0x00, 0x00, // 87
1026  0x9a, 0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, // 88
1027  0x8b, 0x80, 0x40, 0x20, 0x10, 0x0e, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 89
1028  0x9a, 0x00, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x00, 0x00, 0x00, // 90
1029  0xa9, 0x00, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 91
1030  0x9a, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, // 92
1031  0xa9, 0x00, 0x00, 0x82, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, // 93
1032  0x8b, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, // 94
1033  0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 95
1034  0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96
1035  0x8b, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 97
1036  0x8a, 0xfe, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 98
1037  0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x00, 0x00, // 99
1038  0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xfe, 0x00, 0x00, 0x00, // 100
1039  0x8b, 0x1c, 0x22, 0x08, 0x22, 0x08, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 101
1040  0x89, 0x10, 0x00, 0x10, 0x7e, 0x90, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, // 102
1041  0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x7e, 0x00, 0x00, 0x00, // 103
1042  0x8a, 0xfe, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 104
1043  0x98, 0x00, 0x22, 0x00, 0xbe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 105
1044  0x99, 0x00, 0x01, 0x00, 0x01, 0x20, 0x01, 0xbe, 0x00, 0x00, 0x00, 0x00, // 106
1045  0x9a, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x14, 0x00, 0x22, 0x00, 0x00, 0x00, // 107
1046  0x98, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 108
1047  0x8b, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, // 109
1048  0x8a, 0x3e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 110
1049  0x8b, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, // 111
1050  0x0a, 0x7f, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x38, 0x00, 0x00, 0x00, // 112
1051  0x1b, 0x00, 0x38, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x7e, 0x00, 0x00, // 113
1052  0x8a, 0x3e, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, // 114
1053  0x8b, 0x10, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x04, 0x00, 0x00, // 115
1054  0x8a, 0x20, 0x00, 0x7c, 0x02, 0x20, 0x02, 0x20, 0x02, 0x00, 0x00, 0x00, // 116
1055  0x8b, 0x3c, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 117
1056  0x8b, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 118
1057  0x8b, 0x3c, 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x3c, 0x00, 0x00, // 119
1058  0x89, 0x22, 0x14, 0x00, 0x08, 0x00, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, // 120
1059  0x0b, 0x40, 0x20, 0x11, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 121
1060  0x89, 0x22, 0x04, 0x22, 0x08, 0x22, 0x10, 0x22, 0x00, 0x00, 0x00, 0x00, // 122
1061  0xaa, 0x00, 0x00, 0x10, 0x00, 0x6c, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, // 123
1062  0xc7, 0x00, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 124
1063  0xaa, 0x00, 0x82, 0x00, 0x82, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // 125
1064  0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 126
1065  0x8b, 0x7c, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x7c, 0x00, 0x00, // 127
1066  0x8a, 0x04, 0x0a, 0x80, 0x2a, 0x60, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 128
1067  0x8a, 0x0c, 0x12, 0x28, 0x82, 0x68, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 129
1068  0x8a, 0x0c, 0x32, 0x00, 0x82, 0x40, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 130
1069  0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x42, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 131
1070  0x98, 0x00, 0x02, 0x00, 0x16, 0x88, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, // 132
1071  0xa9, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 133
1072  0x8b, 0x12, 0x00, 0x1e, 0x60, 0x12, 0x80, 0x12, 0x80, 0x40, 0x00, 0x00, // 134
1073  0x9a, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, // 135
1074  0x8a, 0x06, 0x01, 0x08, 0x01, 0x10, 0x21, 0x80, 0x02, 0x00, 0x00, 0x00, // 136
1075  0x8b, 0x06, 0x58, 0x80, 0x08, 0x84, 0x40, 0x06, 0x58, 0x80, 0x00, 0x00, // 137
1076  0x8b, 0x12, 0x4c, 0x80, 0x10, 0x80, 0x50, 0x02, 0x4c, 0x80, 0x00, 0x00, // 138
1077  0x8b, 0x02, 0x18, 0x24, 0x80, 0x44, 0x02, 0x48, 0x30, 0x80, 0x00, 0x00, // 139
1078  0x8b, 0x06, 0x38, 0xc0, 0x20, 0x88, 0x26, 0xd8, 0x02, 0x08, 0x00, 0x00, // 140
1079  0x8b, 0x02, 0x04, 0x08, 0x14, 0x40, 0xa4, 0x00, 0xbe, 0x40, 0x00, 0x00, // 141
1080  0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x8a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 142
1081  0x1b, 0x00, 0x18, 0x21, 0x04, 0x41, 0x06, 0x40, 0x04, 0x40, 0x00, 0x00, // 143
1082  0x8b, 0x02, 0x10, 0x6a, 0x00, 0xaa, 0x00, 0xac, 0x10, 0x80, 0x00, 0x00, // 144
1083  0x8a, 0x06, 0x18, 0x60, 0x00, 0x82, 0x10, 0x82, 0x6c, 0x00, 0x00, 0x00, // 145
1084  0x8b, 0x0e, 0x30, 0x40, 0x90, 0x0e, 0x70, 0x82, 0x10, 0x82, 0x00, 0x00, // 146
1085  0x8b, 0x04, 0x22, 0x08, 0x22, 0x1c, 0x22, 0x08, 0x22, 0x10, 0x00, 0x00, // 147
1086  0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00, // 148
1087  0x8a, 0x0c, 0x11, 0x02, 0x2c, 0x12, 0x20, 0x44, 0x18, 0x00, 0x00, 0x00, // 149
1088  0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 150
1089  0x8b, 0x02, 0x04, 0x08, 0x14, 0x80, 0x24, 0x00, 0x3e, 0x80, 0x00, 0x00, // 151
1090  0x8b, 0x0c, 0x12, 0x00, 0xa2, 0x00, 0x22, 0x00, 0xa4, 0x18, 0x00, 0x00, // 152
1091  0x8b, 0x0c, 0x32, 0x00, 0x82, 0x00, 0x02, 0x00, 0x8c, 0x30, 0x00, 0x00, // 153
1092  0x8a, 0x04, 0x0a, 0x20, 0x8a, 0x20, 0x0a, 0x24, 0x9a, 0x00, 0x00, 0x00, // 154
1093  0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x02, 0x00, 0x24, 0x98, 0x00, 0x00, 0x00, // 155
1094  0x8b, 0x0c, 0x32, 0x80, 0x02, 0x00, 0x02, 0x0c, 0xb2, 0x00, 0x00, 0x00, // 156
1095  0x8b, 0x06, 0x18, 0x22, 0x08, 0x22, 0x48, 0x22, 0x80, 0x20, 0x00, 0x00, // 157
1096  0x8a, 0x0c, 0x12, 0x28, 0x02, 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, 0x00, // 158
1097  0x8b, 0x08, 0x20, 0x88, 0x66, 0x18, 0x20, 0x48, 0x20, 0x80, 0x00, 0x00, // 159
1098  0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 160
1099  0x9a, 0x00, 0x02, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 161
1100  0x9a, 0x00, 0x20, 0x40, 0x80, 0x00, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 162
1101  0x8b, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x00, 0x00, // 163
1102  0x8a, 0x00, 0x24, 0x10, 0x46, 0x38, 0xc4, 0x10, 0x48, 0x00, 0x00, 0x00, // 164
1103  0x8b, 0x40, 0x82, 0x44, 0x88, 0x10, 0x22, 0x44, 0x82, 0x04, 0x00, 0x00, // 165
1104  0x8b, 0x0c, 0x10, 0x42, 0xa0, 0x12, 0xa8, 0x44, 0x0a, 0x10, 0x00, 0x00, // 166
1105  0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 167
1106  0xba, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 168
1107  0x98, 0x00, 0x02, 0x00, 0x04, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // 169
1108  0x8b, 0x10, 0x04, 0x50, 0x28, 0x10, 0x28, 0x14, 0x40, 0x10, 0x00, 0x00, // 170
1109  0x8b, 0x10, 0x00, 0x14, 0x08, 0x10, 0x20, 0x50, 0x00, 0x10, 0x00, 0x00, // 171
1110  0x29, 0x00, 0x00, 0x01, 0x04, 0x0a, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // 172
1111  0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 173
1112  0xa8, 0x00, 0x00, 0x02, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // 174
1113  0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 175
1114  0x8b, 0x1c, 0x20, 0x42, 0x00, 0x82, 0x00, 0x84, 0x08, 0x70, 0x00, 0x00, // 176
1115  0x99, 0x00, 0x02, 0x00, 0x46, 0x18, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 177
1116  0x8b, 0x02, 0x40, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x60, 0x00, 0x00, // 178
1117  0x8b, 0x04, 0x00, 0x82, 0x00, 0x92, 0x00, 0xb2, 0x4c, 0x80, 0x00, 0x00, // 179
1118  0x8b, 0x08, 0x10, 0x08, 0x20, 0x08, 0x46, 0x38, 0xc0, 0x08, 0x00, 0x00, // 180
1119  0x8b, 0x04, 0x60, 0x82, 0x20, 0x82, 0x20, 0x84, 0x18, 0x80, 0x00, 0x00, // 181
1120  0x8a, 0x0c, 0x10, 0x22, 0x10, 0x42, 0x10, 0x82, 0x0c, 0x00, 0x00, 0x00, // 182
1121  0x8b, 0x80, 0x02, 0x84, 0x08, 0x90, 0x20, 0x80, 0x40, 0x80, 0x00, 0x00, // 183
1122  0x8b, 0x0c, 0x62, 0x10, 0x82, 0x10, 0x82, 0x10, 0x8c, 0x60, 0x00, 0x00, // 184
1123  0x8a, 0x60, 0x02, 0x90, 0x04, 0x90, 0x08, 0x90, 0x60, 0x00, 0x00, 0x00, // 185
1124  0xa9, 0x00, 0x00, 0x02, 0x14, 0x22, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, // 186
1125  0x2a, 0x00, 0x00, 0x01, 0x04, 0x2a, 0x44, 0x28, 0x40, 0x00, 0x00, 0x00, // 187
1126  0x9a, 0x00, 0x10, 0x08, 0x24, 0x02, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 188
1127  0x8a, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x00, 0x00, 0x00, // 189
1128  0x9a, 0x00, 0x02, 0x00, 0x04, 0x80, 0x48, 0x20, 0x10, 0x00, 0x00, 0x00, // 190
1129  0x8a, 0x48, 0x02, 0x80, 0x08, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, 0x00, // 191
1130  0x8b, 0x1c, 0x20, 0x42, 0x80, 0x12, 0x88, 0x22, 0x88, 0x70, 0x00, 0x00, // 192
1131  0x8b, 0x02, 0x04, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x00, // 193
1132  0x8b, 0x06, 0x98, 0x62, 0x80, 0x12, 0x80, 0x12, 0x8c, 0x60, 0x00, 0x00, // 194
1133  0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x82, 0x00, 0x84, 0x40, 0x00, 0x00, // 195
1134  0x8b, 0x06, 0x98, 0x62, 0x80, 0x02, 0x80, 0x04, 0x88, 0x70, 0x00, 0x00, // 196
1135  0x8b, 0x06, 0x38, 0xc2, 0x10, 0x82, 0x10, 0x82, 0x00, 0x80, 0x00, 0x00, // 197
1136  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x80, 0x10, 0x80, 0x00, 0x80, 0x00, 0x00, // 198
1137  0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x92, 0x04, 0x98, 0x40, 0x00, 0x00, // 199
1138  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x00, 0x10, 0x06, 0x38, 0xc0, 0x00, 0x00, // 200
1139  0x92, 0x00, 0x02, 0x00, 0x86, 0x18, 0xe2, 0x00, 0x80, 0x00, 0x00, 0x00, // 201
1140  0x8b, 0x0c, 0x02, 0x00, 0x02, 0x80, 0x04, 0x98, 0x60, 0x80, 0x00, 0x00, // 202
1141  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x20, 0x08, 0x44, 0x02, 0x80, 0x00, 0x00, // 203
1142  0x9a, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, // 204
1143  0x8b, 0x06, 0x38, 0xc0, 0x00, 0x30, 0x00, 0x46, 0x38, 0xc0, 0x00, 0x00, // 205
1144  0x8b, 0x06, 0x38, 0xc0, 0x20, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 206
1145  0x8b, 0x0c, 0x32, 0x40, 0x82, 0x00, 0x82, 0x04, 0x98, 0x60, 0x00, 0x00, // 207
1146  0x8b, 0x06, 0x18, 0x60, 0x90, 0x00, 0x90, 0x00, 0x90, 0x60, 0x00, 0x00, // 208
1147  0x8b, 0x1c, 0x20, 0x42, 0x00, 0x8a, 0x00, 0x84, 0x0a, 0x70, 0x00, 0x00, // 209
1148  0x8b, 0x06, 0x18, 0x60, 0x80, 0x10, 0x88, 0x14, 0x82, 0x60, 0x00, 0x00, // 210
1149  0x8b, 0x04, 0x62, 0x00, 0x92, 0x00, 0x92, 0x00, 0x8c, 0x40, 0x00, 0x00, // 211
1150  0x8b, 0x80, 0x00, 0x86, 0x18, 0xe0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 212
1151  0x8b, 0x0c, 0x32, 0xc0, 0x02, 0x00, 0x02, 0x0c, 0x30, 0xc0, 0x00, 0x00, // 213
1152  0x9b, 0x00, 0xfe, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 214
1153  0x8b, 0x06, 0x38, 0xc4, 0x08, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 215
1154  0x8b, 0x02, 0x84, 0x48, 0x20, 0x18, 0x24, 0x02, 0x40, 0x80, 0x00, 0x00, // 216
1155  0x8b, 0x80, 0x40, 0x26, 0x18, 0x00, 0x20, 0x00, 0x40, 0x80, 0x00, 0x00, // 217
1156  0x8b, 0x02, 0x04, 0x8a, 0x00, 0x92, 0x00, 0xa2, 0x40, 0x80, 0x00, 0x00, // 218
1157  0x9b, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x80, 0x00, 0x80, 0x00, 0x00, // 219
1158  0xa8, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 220
1159  0x8a, 0x02, 0x00, 0x02, 0x80, 0x06, 0x98, 0x60, 0x80, 0x00, 0x00, 0x00, // 221
1160  0x9a, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00, // 222
1161  0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 223
1162  0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 224
1163  0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 225
1164  0x8a, 0x06, 0x18, 0xe2, 0x00, 0x22, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 226
1165  0x8a, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00, 0x00, // 227
1166  0x8b, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x06, 0x38, 0xc0, 0x00, 0x00, // 228
1167  0x8a, 0x0c, 0x12, 0x28, 0x02, 0x28, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 229
1168  0x8b, 0x20, 0x00, 0x26, 0x18, 0x60, 0x00, 0xa0, 0x00, 0x80, 0x00, 0x00, // 230
1169  0x1b, 0x00, 0x18, 0x25, 0x00, 0x45, 0x00, 0x46, 0x18, 0x60, 0x00, 0x00, // 231
1170  0x8a, 0x06, 0x18, 0xe0, 0x00, 0x20, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 232
1171  0x99, 0x00, 0x02, 0x00, 0x26, 0x18, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, // 233
1172  0x89, 0x01, 0x00, 0x01, 0x00, 0x26, 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, // 234
1173  0x8a, 0x06, 0x18, 0x60, 0x88, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, 0x00, // 235
1174  0x99, 0x00, 0x02, 0x00, 0x06, 0x98, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 236
1175  0x8a, 0x26, 0x18, 0x20, 0x06, 0x38, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 237
1176  0x89, 0x26, 0x18, 0x20, 0x00, 0x20, 0x06, 0x18, 0x00, 0x00, 0x00, 0x00, // 238
1177  0x8a, 0x0c, 0x12, 0x00, 0x20, 0x02, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 239
1178  0x0a, 0x03, 0x1c, 0x60, 0x04, 0x40, 0x04, 0x48, 0x30, 0x00, 0x00, 0x00, // 240
1179  0x1b, 0x00, 0x18, 0x24, 0x00, 0x44, 0x00, 0x47, 0x18, 0x60, 0x00, 0x00, // 241
1180  0x89, 0x06, 0x38, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // 242
1181  0x8a, 0x02, 0x10, 0x02, 0x28, 0x02, 0x28, 0x04, 0x20, 0x00, 0x00, 0x00, // 243
1182  0x9a, 0x00, 0x20, 0x0c, 0x32, 0xc0, 0x22, 0x00, 0x20, 0x00, 0x00, 0x00, // 244
1183  0x8a, 0x0c, 0x32, 0x00, 0x02, 0x00, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 245
1184  0x9a, 0x00, 0x3e, 0x00, 0x04, 0x00, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, // 246
1185  0x8b, 0x0e, 0x30, 0x04, 0x00, 0x18, 0x04, 0x00, 0x06, 0x38, 0x00, 0x00, // 247
1186  0x8b, 0x02, 0x00, 0x24, 0x10, 0x08, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, // 248
1187  0x1b, 0x00, 0x40, 0x21, 0x12, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 249
1188  0x8b, 0x02, 0x00, 0x26, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x20, 0x00, 0x00, // 250
1189  0x9a, 0x00, 0x10, 0x04, 0x1a, 0x60, 0x82, 0x00, 0x80, 0x00, 0x00, 0x00, // 251
1190  0x99, 0x00, 0x02, 0x04, 0x08, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, // 252
1191  0x9a, 0x00, 0x02, 0x00, 0x82, 0x0c, 0xb0, 0x40, 0x10, 0x00, 0x00, 0x00, // 253
1192  0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 254
1193  0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00 // 255
1194 };
1195 
1197  : ImagePrinter(motherBoard_, false)
1198 {
1200 }
1201 
1202 std::string_view ImagePrinterEpson::getName() const
1203 {
1204  return "epson-printer";
1205 }
1206 
1207 std::string_view ImagePrinterEpson::getDescription() const
1208 {
1209  return "Emulate Epson FX80 printer, prints to image.";
1210 }
1211 
1212 std::pair<unsigned, unsigned> ImagePrinterEpson::getNumberOfDots()
1213 {
1214  return {610, 825};
1215 }
1216 
1217 void ImagePrinterEpson::resetSettings()
1218 {
1219  lineFeed = 12.0;
1220  leftBorder = 48;
1221  rightBorder = leftBorder + 480;
1222  graphDensity = 1.0;
1223  fontDensity = 1.0;
1224  pageTop = 48;
1225  lines = 72;
1226  fontWidth = 6;
1227  eightBit = -1;
1228 
1229  memcpy(fontInfo.rom, EpsonFontRom, sizeof(EpsonFontRom));
1230  fontInfo.charWidth = 12;
1231  fontInfo.pixelDelta = 0.5;
1232  fontInfo.useRam = false;
1233 }
1234 
1235 unsigned ImagePrinterEpson::calcEscSequenceLength(byte character)
1236 {
1237  switch (character & 127) {
1238  case '!': case '-': case '/': case '3': case 'A': case 'J':
1239  case 'N': case 'Q': case 'R': case 'S': case 'U': case 'W':
1240  case 'b': case 'i': case 'j': case 'l': case 'p': case 's':
1241  return 1;
1242  case '%': case '?': case 'K': case 'L': case 'Z': case '^':
1243  return 2;
1244  case '*': case ':': case '&':
1245  return 3;
1246  case 'B': // Set tabs, variable length (up to 16 tabs)
1247  return 0;
1248  case 'C': // Set form length, variable length (2 or 3)
1249  return 0;
1250  case 'D': // Set tabs, variable length (up to 32 tabs)
1251  return 0;
1252  default:
1253  return 0;
1254  }
1255 }
1256 
1257 unsigned ImagePrinterEpson::parseNumber(unsigned sizeStart, unsigned sizeChars)
1258 {
1259  unsigned Value = 0;
1260  sizeStart += sizeChars;
1261  while (sizeChars--) {
1262  Value = Value * 256 + abEscSeq[--sizeStart];
1263  }
1264  return Value;
1265 }
1266 
1267 void ImagePrinterEpson::processEscSequence()
1268 {
1269  byte character = abEscSeq[0] & 127;
1270 
1271  switch (character) {
1272  case '!': { // Master Print Mode Select
1273  unsigned masterSelect = parseNumber(1, 1);
1274  elite = (masterSelect & 1) != 0;
1275  compressed = (masterSelect & 4) != 0;
1276  bold = (masterSelect & 8) != 0;
1277  doubleStrike = (masterSelect & 16) != 0;
1278  doubleWidth = (masterSelect & 32) != 0;
1279 
1280  if (elite) {
1281  fontDensity = 1.20;
1282  } else if (compressed) {
1283  fontDensity = 1.72;
1284  } else {
1285  fontDensity = 1.00;
1286  }
1287  break;
1288  }
1289  case '#': // Accept Eight Bit as-is
1290  break;
1291  case '%': // Activates Character Set
1292  fontInfo.useRam = parseNumber(1, 1) & 1;
1293  break;
1294  case '&': // Custom character set, variable length
1295  ramLoadOffset = 12 * parseNumber(2, 1);
1296  ramLoadEnd = 12 * parseNumber(3, 1) + 12;
1297  if (ramLoadEnd <= ramLoadOffset) {
1299  }
1300  break;
1301  case '*': // Turn Graphics Mode ON
1302  ninePinGraphics = false;
1303  switch (parseNumber(1, 1)) {
1304  default:
1305  case 0:
1306  graphDensity = 1.0;
1307  break;
1308  case 1: case 2:
1309  graphDensity = 2.0;
1310  break;
1311  case 3:
1312  graphDensity = 4.0;
1313  break;
1314  case 4:
1315  graphDensity = 1.33;
1316  break;
1317  case 5:
1318  graphDensity = 1.2;
1319  break;
1320  case 6:
1321  graphDensity = 1.5;
1322  break;
1323  }
1324  sizeRemainingDataBytes = parseNumber(2, 2);
1325  break;
1326  case '-': // Turn Underline Mode ON/OFF
1327  underline = parseNumber(1, 1) != 0;
1328  break;
1329  case '/': // Selects Vertical Tab Channel
1330  break;
1331  case '0': // Sets Line Spacing to 1/8 inch
1332  lineFeed = 9.0;
1333  break;
1334  case '1': // Sets Line Spacing to 7/72 inch
1335  lineFeed = 7.0;
1336  break;
1337  case '2': // Sets Line Spacing to 1/6 inch
1338  lineFeed = 12.0;
1339  break;
1340  case '3': // Sets Line Spacing to n/216 inch
1341  lineFeed = (parseNumber(1, 1) & 127) / 3.0;
1342  break;
1343  case '4': // Turn Italic Mode ON
1344  italic = true;
1345  break;
1346  case '5': // Turn Italic Mode OFF
1347  italic = false;
1348  break;
1349  case '6': // Turn Printing of International Italic characters ON
1350  noHighEscapeCodes = true;
1351  break;
1352  case '7': // Turn Printing of International Italic characters OFF
1353  noHighEscapeCodes = false;
1354  break;
1355  case '8': // Turn Paper Out Sensor ON
1356  detectPaperOut = true;
1357  break;
1358  case '9': // Turn Paper Out Sensor OFF
1359  detectPaperOut = false;
1360  break;
1361  case ':': // Copies Rom Character set to RAM
1362  memcpy(fontInfo.ram, fontInfo.rom, sizeof(fontInfo.ram));
1363  break;
1364  case '<': // Turn Uni-directional printing ON (left to right)
1365  leftToRight = true;
1366  break;
1367  case '=': // Sets eight bit to 0
1368  eightBit = 0;
1369  break;
1370  case '>': // Sets eight bit to 1
1371  eightBit = 1;
1372  break;
1373  case '?': // Redefines Graphics Codes
1374  break;
1375  case '@': // Reset
1376  eightBit = -1;
1377  ninePinGraphics = false;
1378  graphDensity = 1.0;
1379  fontDensity = 1.0;
1380  underline = false;
1381  lineFeed = 12.0;
1382  italic = false;
1383  detectPaperOut = false;
1384  leftToRight = false;
1385  doubleStrike = false;
1386  elite = false;
1387  compressed = false;
1388  rightBorder = 6 * 78;
1389  subscript = false;
1390  superscript = false;
1391  doubleWidth = false;
1392  bold = false;
1393  proportional = false;
1394  fontInfo.useRam = false;
1395  noHighEscapeCodes = false;
1396  alternateChar = false;
1397  countryCode = CC_USA;
1398  break;
1399  case 'A': // Sets Line Spacing to n/72 inch
1400  lineFeed = parseNumber(1, 1) & 127;
1401  break;
1402  case 'B': // Set tabs, variable length (up to 16 tabs)
1403  break;
1404  case 'C': // Set form length, variable length (2 or 3)
1405  break;
1406  case 'D': // Set tabs, variable length (up to 32 tabs)
1407  break;
1408  case 'E': // Turn Emphasized Mode ON
1409  bold = true;
1410  break;
1411  case 'F': // Turn Emphasized Mode OFF
1412  bold = false;
1413  break;
1414  case 'G': // Turn Double Strike Mode ON
1415  doubleStrike = true;
1416  break;
1417  case 'H': // Turn Double Strike Mode OFF
1418  doubleStrike = false;
1419  break;
1420  case 'I': // Enables printing of chars 1-31
1421  alternateChar = parseNumber(1, 1) & 1;
1422  break;
1423  case 'J': // Forces Line Feed with n/216 inch
1424  vpos += (parseNumber(1, 1) & 127) / 3.0;
1425  if (vpos >= pageHeight) {
1427  }
1428  break;
1429  case 'K': // Turn Single Density Graphics on (480 dot mode)
1430  graphDensity = 1.0;
1431  ninePinGraphics = false;
1432  sizeRemainingDataBytes = parseNumber(1, 2);
1433  break;
1434  case 'L': // Turn Double Density Graphics on (960 dot mode)
1435  graphDensity = 2.0;
1436  ninePinGraphics = false;
1437  sizeRemainingDataBytes = parseNumber(1, 2);
1438  break;
1439  case 'M': // Turn Elite mode ON
1440  elite = true;
1441  fontDensity = 1.20;
1442  break;
1443  case 'N': // Turn Skip Over Perforation ON
1444  break;
1445  case 'O': // Turn Skip Over Perforation OFF
1446  break;
1447  case 'P': // Turn Elite mode OFF
1448  elite = false;
1449  fontDensity = compressed ? 1.72 : 1.00;
1450  break;
1451  case 'Q': { // Set Right Margin
1452  int width = parseNumber(1, 2);
1453  if (width > 78) width = 78; // FIXME Font dependent !!
1454  rightBorder = 6 * width;
1455  break;
1456  }
1457  case 'R': // Select International Character Set
1458  countryCode = static_cast<CountryCode>(parseNumber(1, 1));
1459  if (countryCode > CC_JAPAN) {
1460  countryCode = CC_USA;
1461  }
1462  break;
1463  case 'S': { // Turn Script Mode ON
1464  int script = parseNumber(1, 1) & 1;
1465  superscript = script == 0;
1466  subscript = script == 1;
1467  break;
1468  }
1469  case 'T': // Turn Script Mode OFF
1470  subscript = false;
1471  superscript = false;
1472  break;
1473  case 'U': // Turn Uni-directional mode ON/OFF
1474  leftToRight = parseNumber(1, 1) != 0;
1475  break;
1476  case 'W': // Turn Expanded Mode ON/OFF
1477  normalAfterLine = false;
1478  doubleWidth = parseNumber(1, 1) != 0;
1479  break;
1480  case 'Y': // Turn High Speed Double Density Graphics ON
1481  break;
1482  case 'Z': // Turns Quadruple Density Graphics ON
1483  graphDensity = 4.0;
1484  ninePinGraphics = false;
1485  sizeRemainingDataBytes = parseNumber(1, 2);
1486  break;
1487  case '^': // Turn Nine Pin Graphics Mode ON
1488  graphDensity = parseNumber(1, 1) ? 2.0 : 1.0;
1489  ninePinGraphics = true;
1490  sizeRemainingDataBytes = 2 * parseNumber(2, 2);
1491  break;
1492  case 'b': // Set Vertical Tab
1493  break;
1494  case 'i': // Turn Immediate Mode ON/OFF
1495  break;
1496  case 'j': // Immediate Reverse Line Feed
1497  vpos -= (parseNumber(1, 1) & 127) / 3.0;
1498  if (vpos < pageTop) {
1499  vpos = pageTop;
1500  }
1501  break;
1502  case 'l': // Set Left Margin
1503  break;
1504  case 'p': // Turn proportional mode ON/OFF
1505  proportional = parseNumber(1, 1) != 0;
1506  break;
1507  case 's': // Set Print Speed
1508  break;
1509  case 127: // Deletes Last Character in Buffer
1510  break;
1511  }
1512 }
1513 
1514 // International character code translation for the Epson FX-80 printer
1515 // US FR DE GB DK SE IT SP JP
1516 static constexpr byte intlChar35 [9] = { 35, 35, 35, 6, 35, 35, 35, 12, 35 };
1517 static constexpr byte intlChar36 [9] = { 36, 36, 36, 36, 36, 11, 36, 36, 36 };
1518 static constexpr byte intlChar64 [9] = { 64, 0, 16, 64, 64, 29, 64, 64, 64 };
1519 static constexpr byte intlChar91 [9] = { 91, 5, 23, 91, 18, 23, 5, 7, 91 };
1520 static constexpr byte intlChar92 [9] = { 92, 15, 24, 92, 20, 24, 92, 9, 31 };
1521 static constexpr byte intlChar93 [9] = { 93, 16, 25, 93, 13, 13, 30, 8, 93 };
1522 static constexpr byte intlChar94 [9] = { 94, 94, 94, 94, 94, 25, 94, 94, 94 };
1523 static constexpr byte intlChar96 [9] = { 96, 96, 96, 96, 96, 30, 2, 96, 96 };
1524 static constexpr byte intlChar123[9] = { 123, 30, 26, 123, 19, 26, 0, 22, 123 };
1525 static constexpr byte intlChar124[9] = { 124, 2, 27, 124, 21, 27, 3, 10, 124 };
1526 static constexpr byte intlChar125[9] = { 125, 1, 28, 125, 14, 14, 1, 125, 125 };
1527 static constexpr byte intlChar126[9] = { 126, 22, 17, 126, 126, 28, 4, 126, 126 };
1528 
1529 void ImagePrinterEpson::processCharacter(byte data)
1530 {
1531  if (data >= 32) {
1532  if (italic) {
1533  data |= 128;
1534  } else {
1535  data &= 127;
1536  }
1537  }
1538 
1539  if (!noHighEscapeCodes && data >= 128 && data < 160) {
1540  data &= 31;
1541  }
1542 
1543  // Convert international characters
1544  switch (data & 0x7f) {
1545  case 35: data = (data & 0x80) | intlChar35 [countryCode]; break;
1546  case 36: data = (data & 0x80) | intlChar36 [countryCode]; break;
1547  case 64: data = (data & 0x80) | intlChar64 [countryCode]; break;
1548  case 91: data = (data & 0x80) | intlChar91 [countryCode]; break;
1549  case 92: data = (data & 0x80) | intlChar92 [countryCode]; break;
1550  case 93: data = (data & 0x80) | intlChar93 [countryCode]; break;
1551  case 94: data = (data & 0x80) | intlChar94 [countryCode]; break;
1552  case 96: data = (data & 0x80) | intlChar96 [countryCode]; break;
1553  case 123: data = (data & 0x80) | intlChar123[countryCode]; break;
1554  case 124: data = (data & 0x80) | intlChar124[countryCode]; break;
1555  case 125: data = (data & 0x80) | intlChar125[countryCode]; break;
1556  case 126: data = (data & 0x80) | intlChar126[countryCode]; break;
1557  }
1558 
1559  if (data >= 32) {
1560  printVisibleCharacter(data);
1561  return;
1562  }
1563 
1564  switch (data) {
1565  case 0: // Terminates horizontal and vertical TAB setting
1566  break;
1567  case 7: // Sound beeper
1568  break;
1569  case 8: // Backspace
1570  // TODO: fix for other font-sizes
1571  hpos -= 8;
1572  if (hpos < leftBorder) {
1573  hpos = leftBorder;
1574  }
1575  break;
1576  case 9: // Horizontal TAB
1577  // TODO: fix for other font-sizes
1578  hpos = ((unsigned(hpos) + 64 - leftBorder) & ~63)
1579  + leftBorder;
1580  if (hpos < rightBorder) {
1581  break;
1582  }
1583  hpos = leftBorder;
1584  [[fallthrough]];
1585  case 10: // Line Feed
1586  case 11: // Vertical TAB
1587  vpos += lineFeed;
1588  if (vpos >= pageHeight) {
1590  }
1591  break;
1592  case 12: // Form Feed
1593  ensurePrintPage();
1595  break;
1596  case 13: // Carrige return
1597  hpos = leftBorder;
1598  break;
1599  case 14: // Turns expanded mode ON
1600  doubleWidth = true;
1601  normalAfterLine = true;
1602  break;
1603  case 15: // Shift in. Emties buffer, turns compressed mode ON (17.16 cpi)
1604  compressed = true;
1605  if (!elite) {
1606  fontDensity = 1.72;
1607  }
1608  break;
1609  case 17: // Device Control 1:
1610  break;
1611  case 18: // Device Control 2: turns compressed mode OFF
1612  compressed = false;
1613  fontDensity = 1.00;
1614  break;
1615  case 19: // Device Control 3:
1616  break;
1617  case 20: // Device Control 4: Turns expanded mode OFF
1618  doubleWidth = false;
1619  break;
1620  case 24: // Cancels all text in the print buffer
1621  break;
1622  case 27: // Escape
1623  escSequence = true;
1624  break;
1625  default:
1626  if (alternateChar) {
1627  printVisibleCharacter(data);
1628  }
1629  break;
1630  }
1631 }
1632 
1633 template<typename Archive>
1634 void ImagePrinterEpson::serialize(Archive& /*ar*/, unsigned /*version*/)
1635 {
1636  // TODO is this worth it?
1637 }
1640 
1641 
1642 // class Paper
1643 
1644 Paper::Paper(unsigned x, unsigned y, double dotSizeX, double dotSizeY)
1645  : buf(x * y)
1646  , sizeX(x), sizeY(y)
1647 {
1648  memset(buf.data(), 255, x * y);
1649  setDotSize(dotSizeX, dotSizeY);
1650 }
1651 
1652 string Paper::save() const
1653 {
1655  "prints", "page", ".png");
1656  VLA(const void*, rowPointers, sizeY);
1657  for (auto y : xrange(sizeY)) {
1658  rowPointers[y] = &buf[sizeX * y];
1659  }
1660  PNG::saveGrayscale(sizeX, sizeY, rowPointers, filename);
1661  return filename;
1662 }
1663 
1664 void Paper::setDotSize(double dotSizeX, double dotSizeY)
1665 {
1666  radiusX = dotSizeX / 2.0;
1667  radiusY = dotSizeY / 2.0;
1668 
1669  int rx = int(16 * radiusX);
1670  int ry = int(16 * radiusY);
1671  radius16 = ry;
1672 
1673  table.clear();
1674  table.resize(2 * (radius16 + 16), -(1 << 30));
1675 
1676  int offset = ry + 16;
1677  int rx2 = 2 * rx * rx;
1678  int ry2 = 2 * ry * ry;
1679 
1680  int x = 0;
1681  int y = ry;
1682  int de_x = ry * ry;
1683  int de_y = (1 - 2 * ry) * rx * rx;
1684  int e = 0;
1685  int sx = 0;
1686  int sy = rx2 * ry;
1687  while (sx <= sy) {
1688  table[offset - y - 1] = x;
1689  table[offset + y ] = x;
1690  x += 1;
1691  sx += ry2;
1692  e += de_x;
1693  de_x += ry2;
1694  if ((2 * e + de_y) > 0) {
1695  y -= 1;
1696  sy -= rx2;
1697  e += de_y;
1698  de_y += rx2;
1699  }
1700  }
1701 
1702  x = rx;
1703  y = 0;
1704  de_x = (1 - 2 * rx) * ry * ry;
1705  de_y = rx * rx;
1706  e = 0;
1707  sx = ry2 * rx;
1708  sy = 0;
1709  while (sy <= sx) {
1710  table[offset - y - 1] = x;
1711  table[offset + y ] = x;
1712  y += 1;
1713  sy += rx2;
1714  e += de_y;
1715  de_y += rx2;
1716  if ((2 * e + de_x) > 0) {
1717  x -= 1;
1718  sx -= ry2;
1719  e += de_x;
1720  de_x += ry2;
1721  }
1722  }
1723 }
1724 
1725 void Paper::plot(double xPos, double yPos)
1726 {
1727  unsigned xx1 = max<int>(int(floor(xPos - radiusX)), 0);
1728  unsigned xx2 = min<int>(int(ceil (xPos + radiusX)), sizeX);
1729  unsigned yy1 = max<int>(int(floor(yPos - radiusY)), 0);
1730  unsigned yy2 = min<int>(int(ceil (yPos + radiusY)), sizeY);
1731 
1732  int y = 16 * yy1 - int(16 * yPos) + 16 + radius16;
1733  for (auto yy : xrange(yy1, yy2)) {
1734  int x = 16 * xx1 - int(16 * xPos);
1735  for (auto xx : xrange(xx1, xx2)) {
1736  int sum = 0;
1737  for (auto i : xrange(16)) {
1738  int a = table[y + i];
1739  if (x < -a) {
1740  int t = 16 + a + x;
1741  if (t > 0) {
1742  sum += min(t, 2 * a);
1743  }
1744  } else {
1745  int t = a - x;
1746  if (t > 0) {
1747  sum += min(16, t);
1748  }
1749  }
1750  }
1751  dot(xx, yy) = max(0, dot(xx, yy) - sum);
1752  x += 16;
1753  }
1754  y += 16;
1755  }
1756 }
1757 
1758 byte& Paper::dot(unsigned x, unsigned y)
1759 {
1760  assert(x < sizeX);
1761  assert(y < sizeY);
1762  return buf[y * sizeX + x];
1763 }
1764 
1765 } // namespace openmsx
Dot Matrix Printer Emulation code mostly copied from blueMSX but changed to: OO-style save to png ima...
TclObject t
void printInfo(std::string_view message)
Definition: CliComm.cc:5
void printWarning(std::string_view message)
Definition: CliComm.cc:10
Represents something you can plug devices into.
Definition: Connector.hh:21
std::string_view getName() const override
Name used to identify this pluggable.
Definition: Printer.cc:1202
void serialize(Archive &ar, unsigned version)
Definition: Printer.cc:1634
ImagePrinterEpson(MSXMotherBoard &motherBoard)
Definition: Printer.cc:1196
std::string_view getDescription() const override
Description for this pluggable.
Definition: Printer.cc:1207
std::string_view getDescription() const override
Description for this pluggable.
Definition: Printer.cc:634
void serialize(Archive &ar, unsigned version)
Definition: Printer.cc:927
std::string_view getName() const override
Name used to identify this pluggable.
Definition: Printer.cc:629
ImagePrinterMSX(MSXMotherBoard &motherBoard)
Definition: Printer.cc:622
void seekPrinterHeadRelative(double offset)
Definition: Printer.cc:238
void resetEmulatedPrinter()
Definition: Printer.cc:200
unsigned remainingCommandBytes
Definition: Printer.hh:112
void plot9Dots(double x, double y, unsigned pattern)
Definition: Printer.cc:209
~ImagePrinter() override
Definition: Printer.cc:155
void write(byte data) override
Definition: Printer.cc:160
unsigned rightBorder
Definition: Printer.hh:110
unsigned sizeRemainingDataBytes
Definition: Printer.hh:114
virtual void processCharacter(byte data)=0
ImagePrinter(MSXMotherBoard &motherBoard, bool graphicsHiLo)
Definition: Printer.cc:113
virtual void resetSettings()=0
void forceFormFeed() override
Definition: Printer.cc:195
void printVisibleCharacter(byte data)
Definition: Printer.cc:300
struct openmsx::ImagePrinter::FontInfo fontInfo
byte abEscSeq[MAX_ESC_CMDSIZE]
Definition: Printer.hh:132
virtual void processEscSequence()=0
void printGraphicByte(byte data)
Definition: Printer.cc:218
unsigned perforationSkip
Definition: Printer.hh:108
void flushEmulatedPrinter()
Definition: Printer.cc:269
virtual std::pair< unsigned, unsigned > getNumberOfDots()=0
virtual unsigned calcEscSequenceLength(byte character)=0
CountryCode countryCode
Definition: Printer.hh:129
unsigned ramLoadOffset
Definition: Printer.hh:115
A Setting with an integer value.
const std::string & getMessage() const &
Definition: MSXException.hh:23
CommandController & getCommandController()
std::shared_ptr< T > getSharedStuff(std::string_view name, Args &&...args)
Some MSX device parts are shared between several MSX devices (e.g.
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:81
std::string save() const
Definition: Printer.cc:1652
Paper(unsigned x, unsigned y, double dotSizeX, double dotSizeY)
Definition: Printer.cc:1644
void plot(double x, double y)
Definition: Printer.cc:1725
void setDotSize(double sizeX, double sizeY)
Definition: Printer.cc:1664
virtual void write(byte data)=0
void setStrobe(bool strobe, EmuTime::param time) override
Sets the strobe signal: false = low, true = high.
Definition: Printer.cc:56
virtual void forceFormFeed()=0
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: Printer.cc:70
void writeData(byte data, EmuTime::param time) override
Sets the data signals.
Definition: Printer.cc:65
void unplugHelper(EmuTime::param time) override
Definition: Printer.cc:75
bool getStatus(EmuTime::param time) override
Returns the STATUS signal: false = low = ready, true = high = not ready.
Definition: Printer.cc:51
constexpr uint8_t reverseByte(uint8_t a)
Reverse the bits in a byte.
Definition: Math.hh:169
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension)
Gets the next numbered file name with the specified prefix in the specified directory,...
void saveGrayscale(unsigned width, unsigned height, const void **rowPointers, const std::string &filename)
Definition: PNG.cc:391
This file implemented 3 utility functions:
Definition: Autofire.cc:5
constexpr byte MSXFontRaw[256 *8]
Definition: Printer.cc:361
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
constexpr const char *const filename
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:124
constexpr byte EpsonFontRom[]
Definition: Printer.cc:937
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983
auto sum(InputRange &&range)
Definition: stl.hh:293
byte ram[256 *MAX_FONT_WIDTH]
Definition: Printer.hh:137
byte rom[256 *MAX_FONT_WIDTH]
Definition: Printer.hh:136
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:10
constexpr auto xrange(T e)
Definition: xrange.hh:155
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:83