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