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 thru: CR/LF
898  }
899  case 10: // LF: Carriage return + Line feed
900  case 11: // VT: Vertical tabulator (like LF)
901  //hpos = leftBorder;
902  vpos += lineFeed;
903  if (vpos >= pageHeight) {
905  }
906  break;
907  case 12: // FF: Form feed
908  ensurePrintPage();
910  break;
911  case 13: // CR: Carriage return
912  hpos = leftBorder;
913  break;
914  case 14: // SO: Double character-width on
915  doubleWidth = true;
916  break;
917  case 15: // SI: Double character-width off
918  doubleWidth = false;
919  break;
920  case 27:
921  escSequence = true;
922  break;
923  default:
924  if (data >= 32) {
925  // Yes, we can print it!
926  printVisibleCharacter(data);
927  }
928  break;
929  }
930  }
931 }
932 
933 template<typename Archive>
934 void ImagePrinterMSX::serialize(Archive& /*ar*/, unsigned /*version*/)
935 {
936  // TODO is this worth it?
937 }
940 
941 
942 // class ImagePrinterEpson
943 
944 static const byte EpsonFontRom[] = {
945  0x8b, 0x04, 0x0a, 0x20, 0x8a, 0x60, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 0
946  0x8b, 0x1c, 0x22, 0x08, 0xa2, 0x48, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 1
947  0x9b, 0x00, 0x3c, 0x00, 0x82, 0x40, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 2
948  0x9a, 0x00, 0x1c, 0x22, 0x80, 0x62, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 3
949  0x96, 0x00, 0x12, 0x80, 0x5e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 4
950  0xa7, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 5
951  0x8b, 0x12, 0x00, 0x7e, 0x80, 0x12, 0x80, 0x02, 0x80, 0x42, 0x00, 0x00, // 6
952  0xc8, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7
953  0x8b, 0x06, 0x00, 0x09, 0x00, 0x51, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // 8
954  0x8b, 0x5e, 0x80, 0x10, 0x80, 0x08, 0x40, 0x04, 0x40, 0x9e, 0x00, 0x00, // 9
955  0x8a, 0x40, 0x9e, 0x00, 0x90, 0x40, 0x10, 0x4e, 0x80, 0x00, 0x00, 0x00, // 10
956  0x8b, 0x92, 0x28, 0x44, 0x00, 0x44, 0x00, 0x44, 0x28, 0x92, 0x00, 0x00, // 11
957  0x8b, 0xfe, 0x00, 0xa0, 0x00, 0x48, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x00, // 12
958  0x8b, 0x06, 0x08, 0x54, 0xa0, 0x04, 0xa0, 0x54, 0x08, 0x06, 0x00, 0x00, // 13
959  0x8b, 0x04, 0x0a, 0x20, 0x0a, 0xa0, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 14
960  0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x46, 0x00, 0x44, 0x00, 0x00, 0x00, // 15
961  0x9a, 0x00, 0x50, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x14, 0x00, 0x00, 0x00, // 16
962  0x8a, 0x7e, 0x80, 0x00, 0x80, 0x12, 0x80, 0x12, 0x6c, 0x00, 0x00, 0x00, // 17
963  0x8b, 0x3e, 0x40, 0x90, 0x00, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x00, // 18
964  0x8b, 0x2c, 0x02, 0x28, 0x02, 0x1c, 0x20, 0x0a, 0x20, 0x1a, 0x00, 0x00, // 19
965  0x8b, 0x3a, 0x44, 0x00, 0x8a, 0x10, 0xa2, 0x00, 0x44, 0xb8, 0x00, 0x00, // 20
966  0x8b, 0x02, 0x08, 0x14, 0x22, 0x08, 0x22, 0x14, 0x08, 0x20, 0x00, 0x00, // 21
967  0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 22
968  0x8b, 0x06, 0x88, 0x14, 0x20, 0x44, 0x20, 0x14, 0x88, 0x06, 0x00, 0x00, // 23
969  0x8b, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, // 24
970  0x8b, 0x3c, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x82, 0x3c, 0x00, 0x00, // 25
971  0x8b, 0x04, 0x0a, 0xa0, 0x0a, 0x20, 0x0a, 0xa0, 0x1c, 0x02, 0x00, 0x00, // 26
972  0x9a, 0x00, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, 0x00, // 27
973  0x8a, 0x3c, 0x80, 0x02, 0x00, 0x02, 0x80, 0x3c, 0x02, 0x00, 0x00, 0x00, // 28
974  0x8b, 0x3e, 0x00, 0x2a, 0x00, 0x6a, 0x80, 0x2a, 0x00, 0x22, 0x00, 0x00, // 29
975  0x8b, 0x1c, 0x22, 0x08, 0x22, 0x48, 0xa2, 0x08, 0x22, 0x18, 0x00, 0x00, // 30
976  0x8b, 0xa8, 0x00, 0x68, 0x00, 0x3e, 0x00, 0x68, 0x00, 0xa8, 0x00, 0x00, // 31
977  0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32
978  0xc8, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 33
979  0xa9, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, // 34
980  0x8b, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0x00, // 35
981  0x8b, 0x24, 0x00, 0x54, 0x00, 0xfe, 0x00, 0x54, 0x00, 0x48, 0x00, 0x00, // 36
982  0x8b, 0xc0, 0x02, 0xc4, 0x08, 0x10, 0x20, 0x46, 0x80, 0x06, 0x00, 0x00, // 37
983  0x8b, 0x4c, 0xa0, 0x12, 0xa0, 0x4a, 0x00, 0x04, 0x08, 0x12, 0x00, 0x00, // 38
984  0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 39
985  0xc9, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, // 40
986  0xa7, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 41
987  0x8b, 0x10, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x10, 0x00, 0x00, // 42
988  0x8b, 0x10, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 43
989  0x39, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, // 44
990  0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 45
991  0xa8, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 46
992  0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 47
993  0x8b, 0x38, 0x44, 0x00, 0x82, 0x00, 0x82, 0x00, 0x44, 0x38, 0x00, 0x00, // 48
994  0xa9, 0x00, 0x00, 0x42, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // 49
995  0x8b, 0x42, 0x80, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x62, 0x00, 0x00, // 50
996  0x8b, 0x84, 0x00, 0x82, 0x00, 0xa2, 0x00, 0xd2, 0x00, 0x8c, 0x00, 0x00, // 51
997  0x8b, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x00, // 52
998  0x8b, 0xe4, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x9c, 0x00, 0x00, // 53
999  0x8b, 0x0c, 0x12, 0x20, 0x52, 0x80, 0x12, 0x00, 0x12, 0x0c, 0x00, 0x00, // 54
1000  0x8b, 0x80, 0x00, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x80, 0x00, 0x00, // 55
1001  0x8b, 0x6c, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x6c, 0x00, 0x00, // 56
1002  0x8b, 0x60, 0x90, 0x00, 0x90, 0x02, 0x94, 0x08, 0x90, 0x60, 0x00, 0x00, // 57
1003  0xa7, 0x00, 0x00, 0x36, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58
1004  0x27, 0x00, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 59
1005  0x89, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 60
1006  0x8b, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, // 61
1007  0xab, 0x00, 0x00, 0x82, 0x00, 0x44, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, // 62
1008  0x8b, 0x40, 0x80, 0x00, 0x80, 0x0a, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, // 63
1009  0x8b, 0x38, 0x44, 0x82, 0x10, 0xaa, 0x00, 0xaa, 0x00, 0x7a, 0x00, 0x00, // 64
1010  0x8b, 0x1e, 0x20, 0x48, 0x80, 0x08, 0x80, 0x48, 0x20, 0x1e, 0x00, 0x00, // 65
1011  0x8b, 0x82, 0x7c, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x6c, 0x00, 0x00, // 66
1012  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x00, 0x00, // 67
1013  0x8b, 0x82, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, // 68
1014  0x8b, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x82, 0x00, 0x00, // 69
1015  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x80, 0x00, 0x00, // 70
1016  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x10, 0x82, 0x10, 0x82, 0x5c, 0x00, 0x00, // 71
1017  0x8b, 0xfe, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x00, // 72
1018  0xa9, 0x00, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 73
1019  0x8a, 0x0c, 0x02, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x80, 0x00, 0x00, 0x00, // 74
1020  0x8b, 0xfe, 0x00, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, // 75
1021  0x8b, 0xfe, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, // 76
1022  0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x20, 0x40, 0x00, 0xfe, 0x00, 0x00, // 77
1023  0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0xfe, 0x00, 0x00, // 78
1024  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x00, 0x00, // 79
1025  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x60, 0x00, 0x00, // 80
1026  0x8b, 0x7c, 0x82, 0x00, 0x82, 0x08, 0x82, 0x04, 0x80, 0x7a, 0x00, 0x00, // 81
1027  0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x98, 0x04, 0x62, 0x00, 0x00, // 82
1028  0x8b, 0x64, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x4c, 0x00, 0x00, // 83
1029  0x8b, 0x80, 0x00, 0x80, 0x00, 0xfe, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 84
1030  0x8b, 0xfc, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xfc, 0x00, 0x00, // 85
1031  0x8b, 0xe0, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0xe0, 0x00, 0x00, // 86
1032  0x8b, 0xfc, 0x02, 0x04, 0x08, 0x30, 0x08, 0x04, 0x02, 0xfc, 0x00, 0x00, // 87
1033  0x9a, 0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, // 88
1034  0x8b, 0x80, 0x40, 0x20, 0x10, 0x0e, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 89
1035  0x9a, 0x00, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x00, 0x00, 0x00, // 90
1036  0xa9, 0x00, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 91
1037  0x9a, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, // 92
1038  0xa9, 0x00, 0x00, 0x82, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, // 93
1039  0x8b, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, // 94
1040  0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 95
1041  0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96
1042  0x8b, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 97
1043  0x8a, 0xfe, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 98
1044  0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x00, 0x00, // 99
1045  0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xfe, 0x00, 0x00, 0x00, // 100
1046  0x8b, 0x1c, 0x22, 0x08, 0x22, 0x08, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 101
1047  0x89, 0x10, 0x00, 0x10, 0x7e, 0x90, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, // 102
1048  0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x7e, 0x00, 0x00, 0x00, // 103
1049  0x8a, 0xfe, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 104
1050  0x98, 0x00, 0x22, 0x00, 0xbe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 105
1051  0x99, 0x00, 0x01, 0x00, 0x01, 0x20, 0x01, 0xbe, 0x00, 0x00, 0x00, 0x00, // 106
1052  0x9a, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x14, 0x00, 0x22, 0x00, 0x00, 0x00, // 107
1053  0x98, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 108
1054  0x8b, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, // 109
1055  0x8a, 0x3e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 110
1056  0x8b, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, // 111
1057  0x0a, 0x7f, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x38, 0x00, 0x00, 0x00, // 112
1058  0x1b, 0x00, 0x38, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x7e, 0x00, 0x00, // 113
1059  0x8a, 0x3e, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, // 114
1060  0x8b, 0x10, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x04, 0x00, 0x00, // 115
1061  0x8a, 0x20, 0x00, 0x7c, 0x02, 0x20, 0x02, 0x20, 0x02, 0x00, 0x00, 0x00, // 116
1062  0x8b, 0x3c, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 117
1063  0x8b, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 118
1064  0x8b, 0x3c, 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x3c, 0x00, 0x00, // 119
1065  0x89, 0x22, 0x14, 0x00, 0x08, 0x00, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, // 120
1066  0x0b, 0x40, 0x20, 0x11, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 121
1067  0x89, 0x22, 0x04, 0x22, 0x08, 0x22, 0x10, 0x22, 0x00, 0x00, 0x00, 0x00, // 122
1068  0xaa, 0x00, 0x00, 0x10, 0x00, 0x6c, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, // 123
1069  0xc7, 0x00, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 124
1070  0xaa, 0x00, 0x82, 0x00, 0x82, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // 125
1071  0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 126
1072  0x8b, 0x7c, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x7c, 0x00, 0x00, // 127
1073  0x8a, 0x04, 0x0a, 0x80, 0x2a, 0x60, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 128
1074  0x8a, 0x0c, 0x12, 0x28, 0x82, 0x68, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 129
1075  0x8a, 0x0c, 0x32, 0x00, 0x82, 0x40, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 130
1076  0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x42, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 131
1077  0x98, 0x00, 0x02, 0x00, 0x16, 0x88, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, // 132
1078  0xa9, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 133
1079  0x8b, 0x12, 0x00, 0x1e, 0x60, 0x12, 0x80, 0x12, 0x80, 0x40, 0x00, 0x00, // 134
1080  0x9a, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, // 135
1081  0x8a, 0x06, 0x01, 0x08, 0x01, 0x10, 0x21, 0x80, 0x02, 0x00, 0x00, 0x00, // 136
1082  0x8b, 0x06, 0x58, 0x80, 0x08, 0x84, 0x40, 0x06, 0x58, 0x80, 0x00, 0x00, // 137
1083  0x8b, 0x12, 0x4c, 0x80, 0x10, 0x80, 0x50, 0x02, 0x4c, 0x80, 0x00, 0x00, // 138
1084  0x8b, 0x02, 0x18, 0x24, 0x80, 0x44, 0x02, 0x48, 0x30, 0x80, 0x00, 0x00, // 139
1085  0x8b, 0x06, 0x38, 0xc0, 0x20, 0x88, 0x26, 0xd8, 0x02, 0x08, 0x00, 0x00, // 140
1086  0x8b, 0x02, 0x04, 0x08, 0x14, 0x40, 0xa4, 0x00, 0xbe, 0x40, 0x00, 0x00, // 141
1087  0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x8a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 142
1088  0x1b, 0x00, 0x18, 0x21, 0x04, 0x41, 0x06, 0x40, 0x04, 0x40, 0x00, 0x00, // 143
1089  0x8b, 0x02, 0x10, 0x6a, 0x00, 0xaa, 0x00, 0xac, 0x10, 0x80, 0x00, 0x00, // 144
1090  0x8a, 0x06, 0x18, 0x60, 0x00, 0x82, 0x10, 0x82, 0x6c, 0x00, 0x00, 0x00, // 145
1091  0x8b, 0x0e, 0x30, 0x40, 0x90, 0x0e, 0x70, 0x82, 0x10, 0x82, 0x00, 0x00, // 146
1092  0x8b, 0x04, 0x22, 0x08, 0x22, 0x1c, 0x22, 0x08, 0x22, 0x10, 0x00, 0x00, // 147
1093  0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00, // 148
1094  0x8a, 0x0c, 0x11, 0x02, 0x2c, 0x12, 0x20, 0x44, 0x18, 0x00, 0x00, 0x00, // 149
1095  0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 150
1096  0x8b, 0x02, 0x04, 0x08, 0x14, 0x80, 0x24, 0x00, 0x3e, 0x80, 0x00, 0x00, // 151
1097  0x8b, 0x0c, 0x12, 0x00, 0xa2, 0x00, 0x22, 0x00, 0xa4, 0x18, 0x00, 0x00, // 152
1098  0x8b, 0x0c, 0x32, 0x00, 0x82, 0x00, 0x02, 0x00, 0x8c, 0x30, 0x00, 0x00, // 153
1099  0x8a, 0x04, 0x0a, 0x20, 0x8a, 0x20, 0x0a, 0x24, 0x9a, 0x00, 0x00, 0x00, // 154
1100  0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x02, 0x00, 0x24, 0x98, 0x00, 0x00, 0x00, // 155
1101  0x8b, 0x0c, 0x32, 0x80, 0x02, 0x00, 0x02, 0x0c, 0xb2, 0x00, 0x00, 0x00, // 156
1102  0x8b, 0x06, 0x18, 0x22, 0x08, 0x22, 0x48, 0x22, 0x80, 0x20, 0x00, 0x00, // 157
1103  0x8a, 0x0c, 0x12, 0x28, 0x02, 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, 0x00, // 158
1104  0x8b, 0x08, 0x20, 0x88, 0x66, 0x18, 0x20, 0x48, 0x20, 0x80, 0x00, 0x00, // 159
1105  0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 160
1106  0x9a, 0x00, 0x02, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 161
1107  0x9a, 0x00, 0x20, 0x40, 0x80, 0x00, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 162
1108  0x8b, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x00, 0x00, // 163
1109  0x8a, 0x00, 0x24, 0x10, 0x46, 0x38, 0xc4, 0x10, 0x48, 0x00, 0x00, 0x00, // 164
1110  0x8b, 0x40, 0x82, 0x44, 0x88, 0x10, 0x22, 0x44, 0x82, 0x04, 0x00, 0x00, // 165
1111  0x8b, 0x0c, 0x10, 0x42, 0xa0, 0x12, 0xa8, 0x44, 0x0a, 0x10, 0x00, 0x00, // 166
1112  0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 167
1113  0xba, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 168
1114  0x98, 0x00, 0x02, 0x00, 0x04, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // 169
1115  0x8b, 0x10, 0x04, 0x50, 0x28, 0x10, 0x28, 0x14, 0x40, 0x10, 0x00, 0x00, // 170
1116  0x8b, 0x10, 0x00, 0x14, 0x08, 0x10, 0x20, 0x50, 0x00, 0x10, 0x00, 0x00, // 171
1117  0x29, 0x00, 0x00, 0x01, 0x04, 0x0a, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // 172
1118  0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 173
1119  0xa8, 0x00, 0x00, 0x02, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // 174
1120  0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 175
1121  0x8b, 0x1c, 0x20, 0x42, 0x00, 0x82, 0x00, 0x84, 0x08, 0x70, 0x00, 0x00, // 176
1122  0x99, 0x00, 0x02, 0x00, 0x46, 0x18, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 177
1123  0x8b, 0x02, 0x40, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x60, 0x00, 0x00, // 178
1124  0x8b, 0x04, 0x00, 0x82, 0x00, 0x92, 0x00, 0xb2, 0x4c, 0x80, 0x00, 0x00, // 179
1125  0x8b, 0x08, 0x10, 0x08, 0x20, 0x08, 0x46, 0x38, 0xc0, 0x08, 0x00, 0x00, // 180
1126  0x8b, 0x04, 0x60, 0x82, 0x20, 0x82, 0x20, 0x84, 0x18, 0x80, 0x00, 0x00, // 181
1127  0x8a, 0x0c, 0x10, 0x22, 0x10, 0x42, 0x10, 0x82, 0x0c, 0x00, 0x00, 0x00, // 182
1128  0x8b, 0x80, 0x02, 0x84, 0x08, 0x90, 0x20, 0x80, 0x40, 0x80, 0x00, 0x00, // 183
1129  0x8b, 0x0c, 0x62, 0x10, 0x82, 0x10, 0x82, 0x10, 0x8c, 0x60, 0x00, 0x00, // 184
1130  0x8a, 0x60, 0x02, 0x90, 0x04, 0x90, 0x08, 0x90, 0x60, 0x00, 0x00, 0x00, // 185
1131  0xa9, 0x00, 0x00, 0x02, 0x14, 0x22, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, // 186
1132  0x2a, 0x00, 0x00, 0x01, 0x04, 0x2a, 0x44, 0x28, 0x40, 0x00, 0x00, 0x00, // 187
1133  0x9a, 0x00, 0x10, 0x08, 0x24, 0x02, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 188
1134  0x8a, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x00, 0x00, 0x00, // 189
1135  0x9a, 0x00, 0x02, 0x00, 0x04, 0x80, 0x48, 0x20, 0x10, 0x00, 0x00, 0x00, // 190
1136  0x8a, 0x48, 0x02, 0x80, 0x08, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, 0x00, // 191
1137  0x8b, 0x1c, 0x20, 0x42, 0x80, 0x12, 0x88, 0x22, 0x88, 0x70, 0x00, 0x00, // 192
1138  0x8b, 0x02, 0x04, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x00, // 193
1139  0x8b, 0x06, 0x98, 0x62, 0x80, 0x12, 0x80, 0x12, 0x8c, 0x60, 0x00, 0x00, // 194
1140  0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x82, 0x00, 0x84, 0x40, 0x00, 0x00, // 195
1141  0x8b, 0x06, 0x98, 0x62, 0x80, 0x02, 0x80, 0x04, 0x88, 0x70, 0x00, 0x00, // 196
1142  0x8b, 0x06, 0x38, 0xc2, 0x10, 0x82, 0x10, 0x82, 0x00, 0x80, 0x00, 0x00, // 197
1143  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x80, 0x10, 0x80, 0x00, 0x80, 0x00, 0x00, // 198
1144  0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x92, 0x04, 0x98, 0x40, 0x00, 0x00, // 199
1145  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x00, 0x10, 0x06, 0x38, 0xc0, 0x00, 0x00, // 200
1146  0x92, 0x00, 0x02, 0x00, 0x86, 0x18, 0xe2, 0x00, 0x80, 0x00, 0x00, 0x00, // 201
1147  0x8b, 0x0c, 0x02, 0x00, 0x02, 0x80, 0x04, 0x98, 0x60, 0x80, 0x00, 0x00, // 202
1148  0x8b, 0x06, 0x38, 0xc0, 0x10, 0x20, 0x08, 0x44, 0x02, 0x80, 0x00, 0x00, // 203
1149  0x9a, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, // 204
1150  0x8b, 0x06, 0x38, 0xc0, 0x00, 0x30, 0x00, 0x46, 0x38, 0xc0, 0x00, 0x00, // 205
1151  0x8b, 0x06, 0x38, 0xc0, 0x20, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 206
1152  0x8b, 0x0c, 0x32, 0x40, 0x82, 0x00, 0x82, 0x04, 0x98, 0x60, 0x00, 0x00, // 207
1153  0x8b, 0x06, 0x18, 0x60, 0x90, 0x00, 0x90, 0x00, 0x90, 0x60, 0x00, 0x00, // 208
1154  0x8b, 0x1c, 0x20, 0x42, 0x00, 0x8a, 0x00, 0x84, 0x0a, 0x70, 0x00, 0x00, // 209
1155  0x8b, 0x06, 0x18, 0x60, 0x80, 0x10, 0x88, 0x14, 0x82, 0x60, 0x00, 0x00, // 210
1156  0x8b, 0x04, 0x62, 0x00, 0x92, 0x00, 0x92, 0x00, 0x8c, 0x40, 0x00, 0x00, // 211
1157  0x8b, 0x80, 0x00, 0x86, 0x18, 0xe0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 212
1158  0x8b, 0x0c, 0x32, 0xc0, 0x02, 0x00, 0x02, 0x0c, 0x30, 0xc0, 0x00, 0x00, // 213
1159  0x9b, 0x00, 0xfe, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 214
1160  0x8b, 0x06, 0x38, 0xc4, 0x08, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 215
1161  0x8b, 0x02, 0x84, 0x48, 0x20, 0x18, 0x24, 0x02, 0x40, 0x80, 0x00, 0x00, // 216
1162  0x8b, 0x80, 0x40, 0x26, 0x18, 0x00, 0x20, 0x00, 0x40, 0x80, 0x00, 0x00, // 217
1163  0x8b, 0x02, 0x04, 0x8a, 0x00, 0x92, 0x00, 0xa2, 0x40, 0x80, 0x00, 0x00, // 218
1164  0x9b, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x80, 0x00, 0x80, 0x00, 0x00, // 219
1165  0xa8, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 220
1166  0x8a, 0x02, 0x00, 0x02, 0x80, 0x06, 0x98, 0x60, 0x80, 0x00, 0x00, 0x00, // 221
1167  0x9a, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00, // 222
1168  0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 223
1169  0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 224
1170  0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 225
1171  0x8a, 0x06, 0x18, 0xe2, 0x00, 0x22, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 226
1172  0x8a, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00, 0x00, // 227
1173  0x8b, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x06, 0x38, 0xc0, 0x00, 0x00, // 228
1174  0x8a, 0x0c, 0x12, 0x28, 0x02, 0x28, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 229
1175  0x8b, 0x20, 0x00, 0x26, 0x18, 0x60, 0x00, 0xa0, 0x00, 0x80, 0x00, 0x00, // 230
1176  0x1b, 0x00, 0x18, 0x25, 0x00, 0x45, 0x00, 0x46, 0x18, 0x60, 0x00, 0x00, // 231
1177  0x8a, 0x06, 0x18, 0xe0, 0x00, 0x20, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 232
1178  0x99, 0x00, 0x02, 0x00, 0x26, 0x18, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, // 233
1179  0x89, 0x01, 0x00, 0x01, 0x00, 0x26, 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, // 234
1180  0x8a, 0x06, 0x18, 0x60, 0x88, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, 0x00, // 235
1181  0x99, 0x00, 0x02, 0x00, 0x06, 0x98, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 236
1182  0x8a, 0x26, 0x18, 0x20, 0x06, 0x38, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 237
1183  0x89, 0x26, 0x18, 0x20, 0x00, 0x20, 0x06, 0x18, 0x00, 0x00, 0x00, 0x00, // 238
1184  0x8a, 0x0c, 0x12, 0x00, 0x20, 0x02, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 239
1185  0x0a, 0x03, 0x1c, 0x60, 0x04, 0x40, 0x04, 0x48, 0x30, 0x00, 0x00, 0x00, // 240
1186  0x1b, 0x00, 0x18, 0x24, 0x00, 0x44, 0x00, 0x47, 0x18, 0x60, 0x00, 0x00, // 241
1187  0x89, 0x06, 0x38, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // 242
1188  0x8a, 0x02, 0x10, 0x02, 0x28, 0x02, 0x28, 0x04, 0x20, 0x00, 0x00, 0x00, // 243
1189  0x9a, 0x00, 0x20, 0x0c, 0x32, 0xc0, 0x22, 0x00, 0x20, 0x00, 0x00, 0x00, // 244
1190  0x8a, 0x0c, 0x32, 0x00, 0x02, 0x00, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 245
1191  0x9a, 0x00, 0x3e, 0x00, 0x04, 0x00, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, // 246
1192  0x8b, 0x0e, 0x30, 0x04, 0x00, 0x18, 0x04, 0x00, 0x06, 0x38, 0x00, 0x00, // 247
1193  0x8b, 0x02, 0x00, 0x24, 0x10, 0x08, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, // 248
1194  0x1b, 0x00, 0x40, 0x21, 0x12, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 249
1195  0x8b, 0x02, 0x00, 0x26, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x20, 0x00, 0x00, // 250
1196  0x9a, 0x00, 0x10, 0x04, 0x1a, 0x60, 0x82, 0x00, 0x80, 0x00, 0x00, 0x00, // 251
1197  0x99, 0x00, 0x02, 0x04, 0x08, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, // 252
1198  0x9a, 0x00, 0x02, 0x00, 0x82, 0x0c, 0xb0, 0x40, 0x10, 0x00, 0x00, 0x00, // 253
1199  0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 254
1200  0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00 // 255
1201 };
1202 
1204  : ImagePrinter(motherBoard_, false)
1205 {
1207 }
1208 
1209 const string& ImagePrinterEpson::getName() const
1210 {
1211  static const string name("epson-printer");
1212  return name;
1213 }
1214 
1216 {
1217  return "Emulate Epson FX80 printer, prints to image.";
1218 }
1219 
1220 void ImagePrinterEpson::getNumberOfDots(unsigned& dotsX, unsigned& dotsY)
1221 {
1222  dotsX = 610;
1223  dotsY = 825;
1224 }
1225 
1226 void ImagePrinterEpson::resetSettings()
1227 {
1228  lineFeed = 12.0;
1229  leftBorder = 48;
1230  rightBorder = leftBorder + 480;
1231  graphDensity = 1.0;
1232  fontDensity = 1.0;
1233  pageTop = 48;
1234  lines = 72;
1235  fontWidth = 6;
1236  eightBit = -1;
1237 
1238  memcpy(fontInfo.rom, EpsonFontRom, sizeof(EpsonFontRom));
1239  fontInfo.charWidth = 12;
1240  fontInfo.pixelDelta = 0.5;
1241  fontInfo.useRam = false;
1242 }
1243 
1244 unsigned ImagePrinterEpson::calcEscSequenceLength(byte character)
1245 {
1246  switch (character & 127) {
1247  case '!': case '-': case '/': case '3': case 'A': case 'J':
1248  case 'N': case 'Q': case 'R': case 'S': case 'U': case 'W':
1249  case 'b': case 'i': case 'j': case 'l': case 'p': case 's':
1250  return 1;
1251  case '%': case '?': case 'K': case 'L': case 'Z': case '^':
1252  return 2;
1253  case '*': case ':': case '&':
1254  return 3;
1255  case 'B': // Set tabs, variable length (up to 16 tabs)
1256  return 0;
1257  case 'C': // Set form length, variable length (2 or 3)
1258  return 0;
1259  case 'D': // Set tabs, variable length (up to 32 tabs)
1260  return 0;
1261  default:
1262  return 0;
1263  }
1264 }
1265 
1266 unsigned ImagePrinterEpson::parseNumber(unsigned sizeStart, unsigned sizeChars)
1267 {
1268  unsigned Value = 0;
1269  sizeStart += sizeChars;
1270  while (sizeChars--) {
1271  Value = Value * 256 + abEscSeq[--sizeStart];
1272  }
1273  return Value;
1274 }
1275 
1276 void ImagePrinterEpson::processEscSequence()
1277 {
1278  byte character = abEscSeq[0] & 127;
1279 
1280  switch (character) {
1281  case '!': { // Master Print Mode Select
1282  unsigned masterSelect = parseNumber(1, 1);
1283  elite = (masterSelect & 1) != 0;
1284  compressed = (masterSelect & 4) != 0;
1285  bold = (masterSelect & 8) != 0;
1286  doubleStrike = (masterSelect & 16) != 0;
1287  doubleWidth = (masterSelect & 32) != 0;
1288 
1289  if (elite) {
1290  fontDensity = 1.20;
1291  } else if (compressed) {
1292  fontDensity = 1.72;
1293  } else {
1294  fontDensity = 1.00;
1295  }
1296  break;
1297  }
1298  case '#': // Accept Eight Bit as-is
1299  break;
1300  case '%': // Activates Character Set
1301  fontInfo.useRam = parseNumber(1, 1) & 1;
1302  break;
1303  case '&': // Custom character set, variable length
1304  ramLoadOffset = 12 * parseNumber(2, 1);
1305  ramLoadEnd = 12 * parseNumber(3, 1) + 12;
1306  if (ramLoadEnd <= ramLoadOffset) {
1308  }
1309  break;
1310  case '*': // Turn Graphics Mode ON
1311  ninePinGraphics = false;
1312  switch (parseNumber(1, 1)) {
1313  default:
1314  case 0:
1315  graphDensity = 1.0;
1316  break;
1317  case 1: case 2:
1318  graphDensity = 2.0;
1319  break;
1320  case 3:
1321  graphDensity = 4.0;
1322  break;
1323  case 4:
1324  graphDensity = 1.33;
1325  break;
1326  case 5:
1327  graphDensity = 1.2;
1328  break;
1329  case 6:
1330  graphDensity = 1.5;
1331  break;
1332  }
1333  sizeRemainingDataBytes = parseNumber(2, 2);
1334  break;
1335  case '-': // Turn Underline Mode ON/OFF
1336  underline = parseNumber(1, 1) != 0;
1337  break;
1338  case '/': // Selects Vertical Tab Channel
1339  break;
1340  case '0': // Sets Line Spacing to 1/8 inch
1341  lineFeed = 9.0;
1342  break;
1343  case '1': // Sets Line Spacing to 7/72 inch
1344  lineFeed = 7.0;
1345  break;
1346  case '2': // Sets Line Spacing to 1/6 inch
1347  lineFeed = 12.0;
1348  break;
1349  case '3': // Sets Line Spacing to n/216 inch
1350  lineFeed = (parseNumber(1, 1) & 127) / 3.0;
1351  break;
1352  case '4': // Turn Italic Mode ON
1353  italic = true;
1354  break;
1355  case '5': // Turn Italic Mode OFF
1356  italic = false;
1357  break;
1358  case '6': // Turn Printing of International Italic characters ON
1359  noHighEscapeCodes = true;
1360  break;
1361  case '7': // Turn Printing of International Italic characters OFF
1362  noHighEscapeCodes = false;
1363  break;
1364  case '8': // Turn Paper Out Sensor ON
1365  detectPaperOut = true;
1366  break;
1367  case '9': // Turn Paper Out Sensor OFF
1368  detectPaperOut = false;
1369  break;
1370  case ':': // Copies Rom Character set to RAM
1371  memcpy(fontInfo.ram, fontInfo.rom, sizeof(fontInfo.ram));
1372  break;
1373  case '<': // Turn Uni-directional printing ON (left to right)
1374  leftToRight = true;
1375  break;
1376  case '=': // Sets eight bit to 0
1377  eightBit = 0;
1378  break;
1379  case '>': // Sets eight bit to 1
1380  eightBit = 1;
1381  break;
1382  case '?': // Redefines Graphics Codes
1383  break;
1384  case '@': // Reset
1385  eightBit = -1;
1386  ninePinGraphics = false;
1387  graphDensity = 1.0;
1388  fontDensity = 1.0;
1389  underline = false;
1390  lineFeed = 12.0;
1391  italic = false;
1392  detectPaperOut = false;
1393  leftToRight = false;
1394  doubleStrike = false;
1395  elite = false;
1396  compressed = false;
1397  rightBorder = 6 * 78;
1398  subscript = false;
1399  superscript = false;
1400  doubleWidth = false;
1401  bold = false;
1402  proportional = false;
1403  fontInfo.useRam = false;
1404  noHighEscapeCodes = false;
1405  alternateChar = false;
1406  countryCode = CC_USA;
1407  break;
1408  case 'A': // Sets Line Spacing to n/72 inch
1409  lineFeed = parseNumber(1, 1) & 127;
1410  break;
1411  case 'B': // Set tabs, variable length (up to 16 tabs)
1412  break;
1413  case 'C': // Set form length, variable length (2 or 3)
1414  break;
1415  case 'D': // Set tabs, variable length (up to 32 tabs)
1416  break;
1417  case 'E': // Turn Emphasized Mode ON
1418  bold = true;
1419  break;
1420  case 'F': // Turn Emphasized Mode OFF
1421  bold = false;
1422  break;
1423  case 'G': // Turn Double Strike Mode ON
1424  doubleStrike = true;
1425  break;
1426  case 'H': // Turn Double Strike Mode OFF
1427  doubleStrike = false;
1428  break;
1429  case 'I': // Enables printing of chars 1-31
1430  alternateChar = parseNumber(1, 1) & 1;
1431  break;
1432  case 'J': // Forces Line Feed with n/216 inch
1433  vpos += (parseNumber(1, 1) & 127) / 3.0;
1434  if (vpos >= pageHeight) {
1436  }
1437  break;
1438  case 'K': // Turn Single Density Graphics on (480 dot mode)
1439  graphDensity = 1.0;
1440  ninePinGraphics = false;
1441  sizeRemainingDataBytes = parseNumber(1, 2);
1442  break;
1443  case 'L': // Turn Double Density Graphics on (960 dot mode)
1444  graphDensity = 2.0;
1445  ninePinGraphics = false;
1446  sizeRemainingDataBytes = parseNumber(1, 2);
1447  break;
1448  case 'M': // Turn Elite mode ON
1449  elite = true;
1450  fontDensity = 1.20;
1451  break;
1452  case 'N': // Turn Skip Over Perforation ON
1453  break;
1454  case 'O': // Turn Skip Over Perforation OFF
1455  break;
1456  case 'P': // Turn Elite mode OFF
1457  elite = false;
1458  fontDensity = compressed ? 1.72 : 1.00;
1459  break;
1460  case 'Q': { // Set Right Margin
1461  int width = parseNumber(1, 2);
1462  if (width > 78) width = 78; // FIXME Font dependent !!
1463  rightBorder = 6 * width;
1464  break;
1465  }
1466  case 'R': // Select International Character Set
1467  countryCode = static_cast<CountryCode>(parseNumber(1, 1));
1468  if (countryCode > CC_JAPAN) {
1469  countryCode = CC_USA;
1470  }
1471  break;
1472  case 'S': { // Turn Script Mode ON
1473  int script = parseNumber(1, 1) & 1;
1474  superscript = script == 0;
1475  subscript = script == 1;
1476  break;
1477  }
1478  case 'T': // Turn Script Mode OFF
1479  subscript = false;
1480  superscript = false;
1481  break;
1482  case 'U': // Turn Uni-directional mode ON/OFF
1483  leftToRight = parseNumber(1, 1) != 0;
1484  break;
1485  case 'W': // Turn Expanded Mode ON/OFF
1486  normalAfterLine = false;
1487  doubleWidth = parseNumber(1, 1) != 0;
1488  break;
1489  case 'Y': // Turn High Speed Double Density Graphics ON
1490  break;
1491  case 'Z': // Turns Quadruple Density Graphics ON
1492  graphDensity = 4.0;
1493  ninePinGraphics = false;
1494  sizeRemainingDataBytes = parseNumber(1, 2);
1495  break;
1496  case '^': // Turn Nine Pin Graphics Mode ON
1497  graphDensity = parseNumber(1, 1) ? 2.0 : 1.0;
1498  ninePinGraphics = true;
1499  sizeRemainingDataBytes = 2 * parseNumber(2, 2);
1500  break;
1501  case 'b': // Set Vertical Tab
1502  break;
1503  case 'i': // Turn Immediate Mode ON/OFF
1504  break;
1505  case 'j': // Immediate Reverse Line Feed
1506  vpos -= (parseNumber(1, 1) & 127) / 3.0;
1507  if (vpos < pageTop) {
1508  vpos = pageTop;
1509  }
1510  break;
1511  case 'l': // Set Left Margin
1512  break;
1513  case 'p': // Turn proportional mode ON/OFF
1514  proportional = parseNumber(1, 1) != 0;
1515  break;
1516  case 's': // Set Print Speed
1517  break;
1518  case 127: // Deletes Last Character in Buffer
1519  break;
1520  }
1521 }
1522 
1523 // International character code translation for the Epson FX-80 printer
1524 // US FR DE GB DK SE IT SP JP
1525 static byte intlChar35 [9] = { 35, 35, 35, 6, 35, 35, 35, 12, 35 };
1526 static byte intlChar36 [9] = { 36, 36, 36, 36, 36, 11, 36, 36, 36 };
1527 static byte intlChar64 [9] = { 64, 0, 16, 64, 64, 29, 64, 64, 64 };
1528 static byte intlChar91 [9] = { 91, 5, 23, 91, 18, 23, 5, 7, 91 };
1529 static byte intlChar92 [9] = { 92, 15, 24, 92, 20, 24, 92, 9, 31 };
1530 static byte intlChar93 [9] = { 93, 16, 25, 93, 13, 13, 30, 8, 93 };
1531 static byte intlChar94 [9] = { 94, 94, 94, 94, 94, 25, 94, 94, 94 };
1532 static byte intlChar96 [9] = { 96, 96, 96, 96, 96, 30, 2, 96, 96 };
1533 static byte intlChar123[9] = { 123, 30, 26, 123, 19, 26, 0, 22, 123 };
1534 static byte intlChar124[9] = { 124, 2, 27, 124, 21, 27, 3, 10, 124 };
1535 static byte intlChar125[9] = { 125, 1, 28, 125, 14, 14, 1, 125, 125 };
1536 static byte intlChar126[9] = { 126, 22, 17, 126, 126, 28, 4, 126, 126 };
1537 
1538 void ImagePrinterEpson::processCharacter(byte data)
1539 {
1540  if (data >= 32) {
1541  if (italic) {
1542  data |= 128;
1543  } else {
1544  data &= 127;
1545  }
1546  }
1547 
1548  if (!noHighEscapeCodes && data >= 128 && data < 160) {
1549  data &= 31;
1550  }
1551 
1552  // Convert international characters
1553  switch (data & 0x7f) {
1554  case 35: data = (data & 0x80) | intlChar35 [countryCode]; break;
1555  case 36: data = (data & 0x80) | intlChar36 [countryCode]; break;
1556  case 64: data = (data & 0x80) | intlChar64 [countryCode]; break;
1557  case 91: data = (data & 0x80) | intlChar91 [countryCode]; break;
1558  case 92: data = (data & 0x80) | intlChar92 [countryCode]; break;
1559  case 93: data = (data & 0x80) | intlChar93 [countryCode]; break;
1560  case 94: data = (data & 0x80) | intlChar94 [countryCode]; break;
1561  case 96: data = (data & 0x80) | intlChar96 [countryCode]; break;
1562  case 123: data = (data & 0x80) | intlChar123[countryCode]; break;
1563  case 124: data = (data & 0x80) | intlChar124[countryCode]; break;
1564  case 125: data = (data & 0x80) | intlChar125[countryCode]; break;
1565  case 126: data = (data & 0x80) | intlChar126[countryCode]; break;
1566  }
1567 
1568  if (data >= 32) {
1569  printVisibleCharacter(data);
1570  return;
1571  }
1572 
1573  switch (data) {
1574  case 0: // Terminates horizontal and vertical TAB setting
1575  break;
1576  case 7: // Sound beeper
1577  break;
1578  case 8: // Backspace
1579  // TODO: fix for other font-sizes
1580  hpos -= 8;
1581  if (hpos < leftBorder) {
1582  hpos = leftBorder;
1583  }
1584  break;
1585  case 9: { // Horizontal TAB
1586  // TODO: fix for other font-sizes
1587  hpos = ((unsigned(hpos) + 64 - leftBorder) & ~63)
1588  + leftBorder;
1589  if (hpos < rightBorder) {
1590  break;
1591  }
1592  hpos = leftBorder;
1593  // fall thru: CR/LF
1594  }
1595  case 10: // Line Feed
1596  case 11: // Vertical TAB
1597  vpos += lineFeed;
1598  if (vpos >= pageHeight) {
1600  }
1601  break;
1602  case 12: // Form Feed
1603  ensurePrintPage();
1605  break;
1606  case 13: // Carrige return
1607  hpos = leftBorder;
1608  break;
1609  case 14: // Turns expanded mode ON
1610  doubleWidth = true;
1611  normalAfterLine = true;
1612  break;
1613  case 15: // Shift in. Emties buffer, turns compressed mode ON (17.16 cpi)
1614  compressed = true;
1615  if (!elite) {
1616  fontDensity = 1.72;
1617  }
1618  break;
1619  case 17: // Device Control 1:
1620  break;
1621  case 18: // Device Control 2: turns compressed mode OFF
1622  compressed = false;
1623  fontDensity = 1.00;
1624  break;
1625  case 19: // Device Control 3:
1626  break;
1627  case 20: // Device Control 4: Turns expanded mode OFF
1628  doubleWidth = false;
1629  break;
1630  case 24: // Cancels all text in the print buffer
1631  break;
1632  case 27: // Escape
1633  escSequence = true;
1634  break;
1635  default:
1636  if (alternateChar) {
1637  printVisibleCharacter(data);
1638  }
1639  break;
1640  }
1641 }
1642 
1643 template<typename Archive>
1644 void ImagePrinterEpson::serialize(Archive& /*ar*/, unsigned /*version*/)
1645 {
1646  // TODO is this worth it?
1647 }
1650 
1651 
1652 // class Paper
1653 
1654 Paper::Paper(unsigned x, unsigned y, double dotSizeX, double dotSizeY)
1655  : buf(x * y)
1656  , sizeX(x), sizeY(y)
1657 {
1658  memset(buf.data(), 255, x * y);
1659  setDotSize(dotSizeX, dotSizeY);
1660 }
1661 
1662 string Paper::save() const
1663 {
1664  string filename = FileOperations::getNextNumberedFileName(
1665  "prints", "page", ".png");
1666  VLA(const void*, rowPointers, sizeY);
1667  for (unsigned y = 0; y < sizeY; ++y) {
1668  rowPointers[y] = &buf[sizeX * y];
1669  }
1670  PNG::saveGrayscale(sizeX, sizeY, rowPointers, filename);
1671  return filename;
1672 }
1673 
1674 void Paper::setDotSize(double dotSizeX, double dotSizeY)
1675 {
1676  radiusX = dotSizeX / 2.0;
1677  radiusY = dotSizeY / 2.0;
1678 
1679  int rx = int(16 * radiusX);
1680  int ry = int(16 * radiusY);
1681  radius16 = ry;
1682 
1683  table.clear();
1684  table.resize(2 * (radius16 + 16), -(1 << 30));
1685 
1686  int offset = ry + 16;
1687  int rx2 = 2 * rx * rx;
1688  int ry2 = 2 * ry * ry;
1689 
1690  int x = 0;
1691  int y = ry;
1692  int de_x = ry * ry;
1693  int de_y = (1 - 2 * ry) * rx * rx;
1694  int e = 0;
1695  int sx = 0;
1696  int sy = rx2 * ry;
1697  while (sx <= sy) {
1698  table[offset - y - 1] = x;
1699  table[offset + y ] = x;
1700  x += 1;
1701  sx += ry2;
1702  e += de_x;
1703  de_x += ry2;
1704  if ((2 * e + de_y) > 0) {
1705  y -= 1;
1706  sy -= rx2;
1707  e += de_y;
1708  de_y += rx2;
1709  }
1710  }
1711 
1712  x = rx;
1713  y = 0;
1714  de_x = (1 - 2 * rx) * ry * ry;
1715  de_y = rx * rx;
1716  e = 0;
1717  sx = ry2 * rx;
1718  sy = 0;
1719  while (sy <= sx) {
1720  table[offset - y - 1] = x;
1721  table[offset + y ] = x;
1722  y += 1;
1723  sy += rx2;
1724  e += de_y;
1725  de_y += rx2;
1726  if ((2 * e + de_x) > 0) {
1727  x -= 1;
1728  sx -= ry2;
1729  e += de_x;
1730  de_x += ry2;
1731  }
1732  }
1733 }
1734 
1735 void Paper::plot(double xPos, double yPos)
1736 {
1737  unsigned xx1 = max<int>(int(floor(xPos - radiusX)), 0);
1738  unsigned xx2 = min<int>(int(ceil (xPos + radiusX)), sizeX);
1739  unsigned yy1 = max<int>(int(floor(yPos - radiusY)), 0);
1740  unsigned yy2 = min<int>(int(ceil (yPos + radiusY)), sizeY);
1741 
1742  int y = 16 * yy1 - int(16 * yPos) + 16 + radius16;
1743  for (unsigned yy = yy1; yy < yy2; ++yy) {
1744  int x = 16 * xx1 - int(16 * xPos);
1745  for (unsigned xx = xx1; xx < xx2; ++xx) {
1746  int sum = 0;
1747  for (int i = 0; i < 16; ++i) {
1748  int a = table[y + i];
1749  if (x < -a) {
1750  int t = 16 + a + x;
1751  if (t > 0) {
1752  sum += min(t, 2 * a);
1753  }
1754  } else {
1755  int t = a - x;
1756  if (t > 0) {
1757  sum += min(16, t);
1758  }
1759  }
1760  }
1761  dot(xx, yy) = max(0, dot(xx, yy) - sum);
1762  x += 16;
1763  }
1764  y += 16;
1765  }
1766 }
1767 
1768 byte& Paper::dot(unsigned x, unsigned y)
1769 {
1770  assert(x < sizeX);
1771  assert(y < sizeY);
1772  return buf[y * sizeX + x];
1773 }
1774 
1775 } // 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:1203
ImagePrinterMSX(MSXMotherBoard &motherBoard)
Definition: Printer.cc:621
std::string save() const
Definition: Printer.cc:1662
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:934
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:1644
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:1209
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:1674
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:1215
void plot(double x, double y)
Definition: Printer.cc:1735
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:1654