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