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