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