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