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