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