@jsenv/terminal-recorder 1.5.6 → 1.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1533 +0,0 @@
1
- import "/jsenv_terminal_recorder_node_modules.js";
2
-
3
- const createLzwEncoder = ({ width, height, pixels, colorDepth }) => {
4
- var EOF = -1;
5
- var imgW;
6
- var imgH;
7
- var pixAry;
8
- var initCodeSize;
9
- var remaining;
10
- var curPixel;
11
-
12
- // GIFCOMPR.C - GIF Image compression routines
13
- // Lempel-Ziv compression based on 'compress'. GIF modifications by
14
- // David Rowley (mgardi@watdcsu.waterloo.edu)
15
- // General DEFINEs
16
-
17
- var BITS = 12;
18
- var HSIZE = 5003; // 80% occupancy
19
-
20
- // GIF Image compression - modified 'compress'
21
- // Based on: compress.c - File compression ala IEEE Computer, June 1984.
22
- // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
23
- // Jim McKie (decvax!mcvax!jim)
24
- // Steve Davies (decvax!vax135!petsd!peora!srd)
25
- // Ken Turkowski (decvax!decwrl!turtlevax!ken)
26
- // James A. Woods (decvax!ihnp4!ames!jaw)
27
- // Joe Orost (decvax!vax135!petsd!joe)
28
-
29
- var n_bits; // number of bits/code
30
- var maxbits = BITS; // user settable max # bits/code
31
- var maxcode; // maximum code, given n_bits
32
- var maxmaxcode = 1 << BITS; // should NEVER generate this code
33
- var htab = [];
34
- var codetab = [];
35
- var hsize = HSIZE; // for dynamic table sizing
36
- var free_ent = 0; // first unused entry
37
-
38
- // block compression parameters -- after all codes are used up,
39
- // and compression rate changes, start over.
40
-
41
- var clear_flg = false;
42
-
43
- // Algorithm: use open addressing double hashing (no chaining) on the
44
- // prefix code / next character combination. We do a variant of Knuth's
45
- // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
46
- // secondary probe. Here, the modular division first probe is gives way
47
- // to a faster exclusive-or manipulation. Also do block compression with
48
- // an adaptive reset, whereby the code table is cleared when the compression
49
- // ratio decreases, but after the table fills. The variable-length output
50
- // codes are re-sized at this point, and a special CLEAR code is generated
51
- // for the decompressor. Late addition: construct the table according to
52
- // file size for noticeable speed improvement on small files. Please direct
53
- // questions about this implementation to ames!jaw.
54
-
55
- var g_init_bits;
56
- var ClearCode;
57
- var EOFCode;
58
-
59
- // output
60
- // Output the given code.
61
- // Inputs:
62
- // code: A n_bits-bit integer. If == -1, then EOF. This assumes
63
- // that n_bits =< wordsize - 1.
64
- // Outputs:
65
- // Outputs code to the file.
66
- // Assumptions:
67
- // Chars are 8 bits long.
68
- // Algorithm:
69
- // Maintain a BITS character long buffer (so that 8 codes will
70
- // fit in it exactly). Use the VAX insv instruction to insert each
71
- // code in turn. When the buffer fills up empty it and start over.
72
-
73
- var cur_accum = 0;
74
- var cur_bits = 0;
75
- var masks = [
76
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
77
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff,
78
- ];
79
-
80
- // Number of characters so far in this 'packet'
81
- var a_count;
82
-
83
- // Define the storage for the packet accumulator
84
- var accum = [];
85
-
86
- imgW = width;
87
- imgH = height;
88
- pixAry = pixels;
89
- initCodeSize = Math.max(2, colorDepth);
90
-
91
- // Add a character to the end of the current packet, and if it is 254
92
- // characters, flush the packet to disk.
93
- const char_out = (c, outs) => {
94
- accum[a_count++] = c;
95
- if (a_count >= 254) flush_char(outs);
96
- };
97
-
98
- // Clear out the hash table
99
- // table clear for block compress
100
- const cl_block = (outs) => {
101
- cl_hash(hsize);
102
- free_ent = ClearCode + 2;
103
- clear_flg = true;
104
- output(ClearCode, outs);
105
- };
106
-
107
- // reset code table
108
- const cl_hash = (hsize) => {
109
- for (var i = 0; i < hsize; ++i) htab[i] = -1;
110
- };
111
-
112
- // Flush the packet to disk, and reset the accumulator
113
- const flush_char = (outs) => {
114
- if (a_count > 0) {
115
- outs.writeByte(a_count);
116
- outs.writeBytes(accum, 0, a_count);
117
- a_count = 0;
118
- }
119
- };
120
-
121
- const MAXCODE = (n_bits) => {
122
- return (1 << n_bits) - 1;
123
- };
124
-
125
- // ----------------------------------------------------------------------------
126
- // Return the next pixel from the image
127
- // ----------------------------------------------------------------------------
128
-
129
- const nextPixel = () => {
130
- if (remaining === 0) return EOF;
131
- --remaining;
132
- var pix = pixAry[curPixel++];
133
- return pix & 0xff;
134
- };
135
-
136
- const output = (code, outs) => {
137
- cur_accum &= masks[cur_bits];
138
-
139
- if (cur_bits > 0) cur_accum |= code << cur_bits;
140
- else cur_accum = code;
141
-
142
- cur_bits += n_bits;
143
-
144
- while (cur_bits >= 8) {
145
- char_out(cur_accum & 0xff, outs);
146
- cur_accum >>= 8;
147
- cur_bits -= 8;
148
- }
149
-
150
- // If the next entry is going to be too big for the code size,
151
- // then increase it, if possible.
152
-
153
- if (free_ent > maxcode || clear_flg) {
154
- if (clear_flg) {
155
- maxcode = MAXCODE((n_bits = g_init_bits));
156
- clear_flg = false;
157
- } else {
158
- ++n_bits;
159
- if (n_bits === maxbits) maxcode = maxmaxcode;
160
- else maxcode = MAXCODE(n_bits);
161
- }
162
- }
163
-
164
- if (code === EOFCode) {
165
- // At EOF, write the rest of the buffer.
166
- while (cur_bits > 0) {
167
- char_out(cur_accum & 0xff, outs);
168
- cur_accum >>= 8;
169
- cur_bits -= 8;
170
- }
171
-
172
- flush_char(outs);
173
- }
174
- };
175
-
176
- const lzwencoder = {
177
- compress: (init_bits, outs) => {
178
- var fcode;
179
- var i; /* = 0 */
180
- var c;
181
- var ent;
182
- var disp;
183
- var hsize_reg;
184
- var hshift;
185
-
186
- // Set up the globals: g_init_bits - initial number of bits
187
- g_init_bits = init_bits;
188
-
189
- // Set up the necessary values
190
- clear_flg = false;
191
- n_bits = g_init_bits;
192
- maxcode = MAXCODE(n_bits);
193
-
194
- ClearCode = 1 << (init_bits - 1);
195
- EOFCode = ClearCode + 1;
196
- free_ent = ClearCode + 2;
197
-
198
- a_count = 0; // clear packet
199
-
200
- ent = nextPixel();
201
-
202
- hshift = 0;
203
- for (fcode = hsize; fcode < 65536; fcode *= 2) ++hshift;
204
- hshift = 8 - hshift; // set hash code range bound
205
-
206
- hsize_reg = hsize;
207
- cl_hash(hsize_reg); // clear hash table
208
-
209
- output(ClearCode, outs);
210
-
211
- outer_loop: while ((c = nextPixel()) !== EOF) {
212
- fcode = (c << maxbits) + ent;
213
- i = (c << hshift) ^ ent; // xor hashing
214
-
215
- if (htab[i] === fcode) {
216
- ent = codetab[i];
217
- continue;
218
- } else if (htab[i] >= 0) {
219
- // non-empty slot
220
-
221
- disp = hsize_reg - i; // secondary hash (after G. Knott)
222
- if (i === 0) disp = 1;
223
-
224
- do {
225
- if ((i -= disp) < 0) i += hsize_reg;
226
-
227
- if (htab[i] === fcode) {
228
- ent = codetab[i];
229
- continue outer_loop;
230
- }
231
- } while (htab[i] >= 0);
232
- }
233
-
234
- output(ent, outs);
235
- ent = c;
236
- if (free_ent < maxmaxcode) {
237
- codetab[i] = free_ent++; // code -> hashtable
238
- htab[i] = fcode;
239
- } else cl_block(outs);
240
- }
241
-
242
- // Put out the final code.
243
- output(ent, outs);
244
- output(EOFCode, outs);
245
- },
246
- encode: (os) => {
247
- os.writeByte(initCodeSize); // write "initial code size" byte
248
- remaining = imgW * imgH; // reset navigation variables
249
- curPixel = 0;
250
- lzwencoder.compress(initCodeSize + 1, os); // compress and write the pixel data
251
- os.writeByte(0); // write block terminator
252
- },
253
- };
254
- return lzwencoder;
255
- };
256
-
257
- /*
258
- * NeuQuant Neural-Net Quantization Algorithm
259
- * ------------------------------------------
260
- *
261
- * Copyright (c) 1994 Anthony Dekker
262
- *
263
- * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See
264
- * "Kohonen neural networks for optimal colour quantization" in "Network:
265
- * Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of
266
- * the algorithm.
267
- *
268
- * Any party obtaining a copy of these files from the author, directly or
269
- * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
270
- * world-wide, paid up, royalty-free, nonexclusive right and license to deal in
271
- * this software and documentation files (the "Software"), including without
272
- * limitation the rights to use, copy, modify, merge, publish, distribute,
273
- * sublicense, and/or sell copies of the Software, and to permit persons who
274
- * receive copies from any such party to do so, with the only requirement being
275
- * that this copyright notice remain intact.
276
- */
277
-
278
- /*
279
- * This class handles Neural-Net quantization algorithm
280
- * @author Kevin Weiner (original Java version - kweiner@fmsware.com)
281
- * @author Thibault Imbert (AS3 version - bytearray.org)
282
- * @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
283
- * @version 0.1 AS3 implementation
284
- */
285
-
286
- const createNeuQuant = ({ pixels, len, sample }) => {
287
- var netsize = 256; /* number of colours used */
288
-
289
- /* four primes near 500 - assume no image has a length so large */
290
- /* that it is divisible by all four primes */
291
-
292
- var prime1 = 499;
293
- var prime2 = 491;
294
- var prime3 = 487;
295
- var prime4 = 503;
296
- var minpicturebytes = 3 * prime4; /* minimum size for input image */
297
-
298
- /*
299
- * Program Skeleton ---------------- [select samplefac in range 1..30] [read
300
- * image from input file] pic = (unsigned char*) malloc(3*width*height);
301
- * initnet(pic,3*width*height,samplefac); learn(); unbiasnet(); [write output
302
- * image header, using writecolourmap(f)] inxbuild(); write output image using
303
- * inxsearch(b,g,r)
304
- */
305
-
306
- /*
307
- * Network Definitions -------------------
308
- */
309
-
310
- var maxnetpos = netsize - 1;
311
- var netbiasshift = 4; /* bias for colour values */
312
- var ncycles = 100; /* no. of learning cycles */
313
-
314
- /* defs for freq and bias */
315
- var intbiasshift = 16; /* bias for fractions */
316
- var intbias = 1 << intbiasshift;
317
- var gammashift = 10; /* gamma = 1024 */
318
- var betashift = 10;
319
- var beta = intbias >> betashift; /* beta = 1/1024 */
320
- var betagamma = intbias << (gammashift - betashift);
321
-
322
- /* defs for decreasing radius factor */
323
- var initrad = netsize >> 3; /* for 256 cols, radius starts */
324
- var radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
325
- var radiusbias = 1 << radiusbiasshift;
326
- var initradius = initrad * radiusbias; /* and decreases by a */
327
- var radiusdec = 30; /* factor of 1/30 each cycle */
328
-
329
- /* defs for decreasing alpha factor */
330
- var alphabiasshift = 10; /* alpha starts at 1.0 */
331
- var initalpha = 1 << alphabiasshift;
332
- var alphadec; /* biased by 10 bits */
333
-
334
- /* radbias and alpharadbias used for radpower calculation */
335
- var radbiasshift = 8;
336
- var radbias = 1 << radbiasshift;
337
- var alpharadbshift = alphabiasshift + radbiasshift;
338
- var alpharadbias = 1 << alpharadbshift;
339
-
340
- /*
341
- * Types and Global Variables --------------------------
342
- */
343
-
344
- var thepicture; /* the input image itself */
345
- var lengthcount; /* lengthcount = H*W*3 */
346
- var samplefac; /* sampling factor 1..30 */
347
-
348
- // typedef int pixel[4]; /* BGRc */
349
- var network; /* the network itself - [netsize][4] */
350
- var netindex = [];
351
-
352
- /* for network lookup - really 256 */
353
- var bias = [];
354
-
355
- /* bias and freq arrays for learning */
356
- var freq = [];
357
- var radpower = [];
358
-
359
- var i;
360
- var p;
361
- thepicture = pixels;
362
- lengthcount = len;
363
- samplefac = sample;
364
- network = new Array(netsize);
365
-
366
- for (i = 0; i < netsize; i++) {
367
- network[i] = new Array(4);
368
- p = network[i];
369
- p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
370
- freq[i] = intbias / netsize; /* 1/netsize */
371
- bias[i] = 0;
372
- }
373
-
374
- const colorMap = () => {
375
- var map = [];
376
- var index = new Array(netsize);
377
-
378
- for (var i = 0; i < netsize; i++) index[network[i][3]] = i;
379
-
380
- var k = 0;
381
- for (var l = 0; l < netsize; l++) {
382
- var j = index[l];
383
- map[k++] = network[j][0];
384
- map[k++] = network[j][1];
385
- map[k++] = network[j][2];
386
- }
387
-
388
- return map;
389
- };
390
-
391
- /*
392
- * Insertion sort of network and building of netindex[0..255] (to do after
393
- * unbias)
394
- * -------------------------------------------------------------------------------
395
- */
396
-
397
- const inxbuild = () => {
398
- var i;
399
- var j;
400
- var smallpos;
401
- var smallval;
402
- var p;
403
- var q;
404
- var previouscol;
405
- var startpos;
406
-
407
- previouscol = 0;
408
- startpos = 0;
409
- for (i = 0; i < netsize; i++) {
410
- p = network[i];
411
- smallpos = i;
412
- smallval = p[1]; /* index on g */
413
-
414
- /* find smallest in i..netsize-1 */
415
- for (j = i + 1; j < netsize; j++) {
416
- q = network[j];
417
- if (q[1] < smallval) {
418
- /* index on g */
419
- smallpos = j;
420
- smallval = q[1]; /* index on g */
421
- }
422
- }
423
- q = network[smallpos];
424
-
425
- /* swap p (i) and q (smallpos) entries */
426
- if (i !== smallpos) {
427
- j = q[0];
428
- q[0] = p[0];
429
- p[0] = j;
430
- j = q[1];
431
- q[1] = p[1];
432
- p[1] = j;
433
- j = q[2];
434
- q[2] = p[2];
435
- p[2] = j;
436
- j = q[3];
437
- q[3] = p[3];
438
- p[3] = j;
439
- }
440
-
441
- /* smallval entry is now in position i */
442
-
443
- if (smallval !== previouscol) {
444
- netindex[previouscol] = (startpos + i) >> 1;
445
-
446
- for (j = previouscol + 1; j < smallval; j++) netindex[j] = i;
447
-
448
- previouscol = smallval;
449
- startpos = i;
450
- }
451
- }
452
-
453
- netindex[previouscol] = (startpos + maxnetpos) >> 1;
454
- for (j = previouscol + 1; j < 256; j++)
455
- netindex[j] = maxnetpos; /* really 256 */
456
- };
457
-
458
- /*
459
- * Main Learning Loop ------------------
460
- */
461
- const learn = () => {
462
- var i;
463
- var j;
464
- var b;
465
- var g;
466
- var r;
467
- var radius;
468
- var rad;
469
- var alpha;
470
- var step;
471
- var delta;
472
- var samplepixels;
473
- var p;
474
- var pix;
475
- var lim;
476
-
477
- if (lengthcount < minpicturebytes) samplefac = 1;
478
-
479
- alphadec = 30 + (samplefac - 1) / 3;
480
- p = thepicture;
481
- pix = 0;
482
- lim = lengthcount;
483
- samplepixels = lengthcount / (3 * samplefac);
484
- delta = (samplepixels / ncycles) | 0;
485
- alpha = initalpha;
486
- radius = initradius;
487
-
488
- rad = radius >> radiusbiasshift;
489
- if (rad <= 1) rad = 0;
490
-
491
- for (i = 0; i < rad; i++)
492
- radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
493
-
494
- if (lengthcount < minpicturebytes) {
495
- step = 3;
496
- } else if (lengthcount % prime1 !== 0) {
497
- step = 3 * prime1;
498
- } else if (lengthcount % prime2 === 0) {
499
- if (lengthcount % prime3 === 0) {
500
- step = 3 * prime4;
501
- } else {
502
- step = 3 * prime3;
503
- }
504
- } else {
505
- step = 3 * prime2;
506
- }
507
-
508
- i = 0;
509
- while (i < samplepixels) {
510
- b = (p[pix + 0] & 0xff) << netbiasshift;
511
- g = (p[pix + 1] & 0xff) << netbiasshift;
512
- r = (p[pix + 2] & 0xff) << netbiasshift;
513
- j = contest(b, g, r);
514
-
515
- altersingle(alpha, j, b, g, r);
516
- if (rad !== 0) alterneigh(rad, j, b, g, r); /* alter neighbours */
517
-
518
- pix += step;
519
- if (pix >= lim) pix -= lengthcount;
520
-
521
- i++;
522
-
523
- if (delta === 0) delta = 1;
524
-
525
- if (i % delta === 0) {
526
- alpha -= alpha / alphadec;
527
- radius -= radius / radiusdec;
528
- rad = radius >> radiusbiasshift;
529
-
530
- if (rad <= 1) rad = 0;
531
-
532
- for (j = 0; j < rad; j++)
533
- radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
534
- }
535
- }
536
- };
537
-
538
- /*
539
- * Unbias network to give byte values 0..255 and record position i to prepare
540
- * for sort
541
- * -----------------------------------------------------------------------------------
542
- */
543
- const unbiasnet = () => {
544
- let i = 0;
545
- while (i < netsize) {
546
- network[i][0] >>= netbiasshift;
547
- network[i][1] >>= netbiasshift;
548
- network[i][2] >>= netbiasshift;
549
- network[i][3] = i; /* record colour no */
550
- i++;
551
- }
552
- };
553
-
554
- /*
555
- * Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in
556
- * radpower[|i-j|]
557
- * ---------------------------------------------------------------------------------
558
- */
559
- const alterneigh = (rad, i, b, g, r) => {
560
- var j;
561
- var k;
562
- var lo;
563
- var hi;
564
- var a;
565
- var m;
566
- var p;
567
-
568
- lo = i - rad;
569
- if (lo < -1) lo = -1;
570
-
571
- hi = i + rad;
572
- if (hi > netsize) hi = netsize;
573
-
574
- j = i + 1;
575
- k = i - 1;
576
- m = 1;
577
-
578
- while (j < hi || k > lo) {
579
- a = radpower[m++];
580
-
581
- if (j < hi) {
582
- p = network[j++];
583
-
584
- try {
585
- p[0] -= (a * (p[0] - b)) / alpharadbias;
586
- p[1] -= (a * (p[1] - g)) / alpharadbias;
587
- p[2] -= (a * (p[2] - r)) / alpharadbias;
588
- } catch (e) {} // prevents 1.3 miscompilation
589
- }
590
-
591
- if (k > lo) {
592
- p = network[k--];
593
-
594
- try {
595
- p[0] -= (a * (p[0] - b)) / alpharadbias;
596
- p[1] -= (a * (p[1] - g)) / alpharadbias;
597
- p[2] -= (a * (p[2] - r)) / alpharadbias;
598
- } catch (e) {}
599
- }
600
- }
601
- };
602
-
603
- /*
604
- * Move neuron i towards biased (b,g,r) by factor alpha
605
- * ----------------------------------------------------
606
- */
607
- const altersingle = (alpha, i, b, g, r) => {
608
- /* alter hit neuron */
609
- var n = network[i];
610
- n[0] -= (alpha * (n[0] - b)) / initalpha;
611
- n[1] -= (alpha * (n[1] - g)) / initalpha;
612
- n[2] -= (alpha * (n[2] - r)) / initalpha;
613
- };
614
-
615
- /*
616
- * Search for biased BGR values ----------------------------
617
- */
618
- const contest = (b, g, r) => {
619
- /* finds closest neuron (min dist) and updates freq */
620
- /* finds best neuron (min dist-bias) and returns position */
621
- /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
622
- /* bias[i] = gamma*((1/netsize)-freq[i]) */
623
-
624
- var i;
625
- var dist;
626
- var a;
627
- var biasdist;
628
- var betafreq;
629
- var bestpos;
630
- var bestbiaspos;
631
- var bestd;
632
- var bestbiasd;
633
- var n;
634
-
635
- bestd = 2147483647;
636
- bestbiasd = bestd;
637
- bestpos = -1;
638
- bestbiaspos = bestpos;
639
-
640
- for (i = 0; i < netsize; i++) {
641
- n = network[i];
642
- dist = n[0] - b;
643
- if (dist < 0) dist = -dist;
644
- a = n[1] - g;
645
- if (a < 0) a = -a;
646
- dist += a;
647
- a = n[2] - r;
648
- if (a < 0) a = -a;
649
- dist += a;
650
-
651
- if (dist < bestd) {
652
- bestd = dist;
653
- bestpos = i;
654
- }
655
-
656
- biasdist = dist - (bias[i] >> (intbiasshift - netbiasshift));
657
-
658
- if (biasdist < bestbiasd) {
659
- bestbiasd = biasdist;
660
- bestbiaspos = i;
661
- }
662
-
663
- betafreq = freq[i] >> betashift;
664
- freq[i] -= betafreq;
665
- bias[i] += betafreq << gammashift;
666
- }
667
-
668
- freq[bestpos] += beta;
669
- bias[bestpos] -= betagamma;
670
- return bestbiaspos;
671
- };
672
-
673
- const neuquant = {
674
- /*
675
- ** Search for BGR values 0..255 (after net is unbiased) and return colour
676
- * index
677
- * ----------------------------------------------------------------------------
678
- */
679
- map: (b, g, r) => {
680
- var i;
681
- var j;
682
- var dist;
683
- var a;
684
- var bestd;
685
- var p;
686
- var best;
687
-
688
- bestd = 1000; /* biggest possible dist is 256*3 */
689
- best = -1;
690
- i = netindex[g]; /* index on g */
691
- j = i - 1; /* start at netindex[g] and work outwards */
692
-
693
- while (i < netsize || j >= 0) {
694
- if (i < netsize) {
695
- p = network[i];
696
- dist = p[1] - g; /* inx key */
697
-
698
- if (dist >= bestd) i = netsize; /* stop iter */
699
- else {
700
- i++;
701
- if (dist < 0) dist = -dist;
702
- a = p[0] - b;
703
- if (a < 0) a = -a;
704
- dist += a;
705
-
706
- if (dist < bestd) {
707
- a = p[2] - r;
708
- if (a < 0) a = -a;
709
- dist += a;
710
-
711
- if (dist < bestd) {
712
- bestd = dist;
713
- best = p[3];
714
- }
715
- }
716
- }
717
- }
718
-
719
- if (j >= 0) {
720
- p = network[j];
721
- dist = g - p[1]; /* inx key - reverse dif */
722
-
723
- if (dist >= bestd) j = -1; /* stop iter */
724
- else {
725
- j--;
726
- if (dist < 0) dist = -dist;
727
- a = p[0] - b;
728
- if (a < 0) a = -a;
729
- dist += a;
730
-
731
- if (dist < bestd) {
732
- a = p[2] - r;
733
- if (a < 0) a = -a;
734
- dist += a;
735
- if (dist < bestd) {
736
- bestd = dist;
737
- best = p[3];
738
- }
739
- }
740
- }
741
- }
742
- }
743
-
744
- return best;
745
- },
746
- process: () => {
747
- learn();
748
- unbiasnet();
749
- inxbuild();
750
- return colorMap();
751
- },
752
- };
753
- return neuquant;
754
- };
755
-
756
- // https://github.com/incubated-geek-cc/video-to-GIF/blob/main/js/GIFEncoder.js
757
- // https://github.com/jnordberg/gif.js
758
- // https://github.com/jnordberg/gif.js/blob/master/src/GIFEncoder.js
759
-
760
-
761
- const createGifEncoder = ({
762
- width,
763
- height,
764
- /*
765
- * Sets quality of color quantization (conversion of images to the maximum 256
766
- * colors allowed by the GIF specification). Lower values (minimum = 1)
767
- * produce better colors, but slow processing significantly. 10 is the
768
- * default, and produces good color mapping at reasonable speeds. Values
769
- * greater than 20 do not yield significant improvements in speed.
770
- */
771
- quality = 10,
772
- /**
773
- * Sets the number of times the set of GIF frames should be played.
774
- * -1 means no repeat, 0 means indefinitely
775
- *
776
- * int number of iterations.
777
- */
778
- repeat = -1,
779
- comment = "",
780
- }) => {
781
- const byteArray = [];
782
- const writeByte = (data) => {
783
- byteArray.push(data);
784
- };
785
- const writeUTFBytes = (string) => {
786
- let i = 0;
787
- while (i < string.length) {
788
- writeByte(string.charCodeAt(i));
789
- i++;
790
- }
791
- };
792
- const writeBytes = (array, offset = 0, length = array.length) => {
793
- let i = offset;
794
- while (i < length) {
795
- writeByte(array[i]);
796
- i++;
797
- }
798
- };
799
- let charCodeMap;
800
- const fillCharCodes = () => {
801
- if (charCodeMap) {
802
- return;
803
- }
804
- charCodeMap = new Map();
805
- let i = 0;
806
- while (i < 256) {
807
- charCodeMap.set(i, String.fromCharCode(i));
808
- i++;
809
- }
810
- };
811
- const readAsBinaryString = () => {
812
- fillCharCodes();
813
- let binaryString = "";
814
- for (const byte of byteArray) {
815
- binaryString += charCodeMap.get(byte);
816
- }
817
- return binaryString;
818
- };
819
-
820
- let transparent = null; // transparent color if given
821
- let transIndex = 0; // transparent index in color table
822
- let colorDepth; // number of bit planes
823
- let usedEntry = []; // active palette entries
824
- let palSize = 7; // color table size (bits-1)
825
- let dispose = -1; // disposal code (-1 = use default
826
- let firstFrame = true;
827
- let finished = false;
828
-
829
- const writeShort = (pValue) => {
830
- writeByte(pValue & 0xff);
831
- writeByte((pValue >> 8) & 0xff);
832
- };
833
-
834
- const encoder = {
835
- /**
836
- * Sets the GIF frame disposal code for the last added frame and any
837
- * subsequent frames. Default is 0 if no transparent color has been set,
838
- * otherwise 2.
839
- * @param code
840
- * int disposal code.
841
- */
842
- setDispose: (code) => {
843
- if (code >= 0) dispose = code;
844
- },
845
-
846
- /**
847
- * Sets the transparent color for the last added frame and any subsequent
848
- * frames. Since all colors are subject to modification in the quantization
849
- * process, the color in the final palette for each frame closest to the given
850
- * color becomes the transparent color for that frame. May be set to null to
851
- * indicate no transparent color.
852
- * @param
853
- * Color to be treated as transparent on display.
854
- */
855
- setTransparent: (c) => {
856
- transparent = c;
857
- },
858
-
859
- /**
860
- * The addFrame method takes an incoming BitmapData object to create each frames
861
- * @param
862
- * BitmapData object to be treated as a GIF's frame
863
- */
864
- addFrame: (context, options) => {
865
- let delay = 0;
866
- if (options) {
867
- if (options.quality) {
868
- quality = options.quality < 1 ? 1 : options.quality;
869
- }
870
- if (options.delay) {
871
- delay = Math.round(options.delay / 10);
872
- }
873
- }
874
-
875
- const canvas = context.canvas;
876
- try {
877
- const imageData = context.getImageData(
878
- 0,
879
- 0,
880
- canvas.width,
881
- canvas.height,
882
- ).data;
883
-
884
- const pixels = [];
885
- // build pixels
886
- {
887
- var count = 0;
888
- let y = 0;
889
- while (y < height) {
890
- let x = 0;
891
- while (x < width) {
892
- const b = y * width * 4 + x * 4;
893
- pixels[count++] = imageData[b];
894
- pixels[count++] = imageData[b + 1];
895
- pixels[count++] = imageData[b + 2];
896
- x++;
897
- }
898
- y++;
899
- }
900
- }
901
- let colorTab;
902
- let indexedPixels = [];
903
- // analyze pixels ( build color table & map pixels)
904
- {
905
- var len = pixels.length;
906
- var nPix = len / 3;
907
- const neuQuant = createNeuQuant({
908
- pixels,
909
- len,
910
- sample: quality,
911
- });
912
-
913
- // initialize quantizer
914
- colorTab = neuQuant.process(); // create reduced palette
915
-
916
- // map image pixels to new palette
917
- var k = 0;
918
- for (var j = 0; j < nPix; j++) {
919
- var index = neuQuant.map(
920
- pixels[k++] & 0xff,
921
- pixels[k++] & 0xff,
922
- pixels[k++] & 0xff,
923
- );
924
- usedEntry[index] = true;
925
- indexedPixels[j] = index;
926
- }
927
-
928
- pixels.length = 0;
929
- colorDepth = 8;
930
- palSize = 7;
931
-
932
- // get closest match to transparent color if specified
933
- if (transparent !== null) {
934
- /**
935
- * Returns index of palette color closest to c
936
- */
937
- const findClosest = (c) => {
938
- var r = (c & 0xff0000) >> 16;
939
- var g = (c & 0x00ff00) >> 8;
940
- var b = c & 0x0000ff;
941
- var minpos = 0;
942
- var dmin = 256 * 256 * 256;
943
- var len = colorTab.length;
944
-
945
- for (var i = 0; i < len; ) {
946
- var dr = r - (colorTab[i++] & 0xff);
947
- var dg = g - (colorTab[i++] & 0xff);
948
- var db = b - (colorTab[i] & 0xff);
949
- var d = dr * dr + dg * dg + db * db;
950
- var index = i / 3;
951
- if (usedEntry[index] && d < dmin) {
952
- dmin = d;
953
- minpos = index;
954
- }
955
- i++;
956
- }
957
- return minpos;
958
- };
959
- transIndex = colorTab === null ? -1 : findClosest(transparent);
960
- }
961
- }
962
-
963
- const writePalette = () => {
964
- writeBytes(colorTab);
965
- var n = 3 * 256 - colorTab.length;
966
- for (var i = 0; i < n; i++) writeByte(0);
967
- };
968
-
969
- if (firstFrame) {
970
- // write logical screen descriptior
971
- {
972
- // logical screen size
973
- writeShort(width);
974
- writeShort(height);
975
- // packed fields
976
- writeByte(
977
- 0x80 | // 1 : global color table flag = 1 (gct used)
978
- 0x70 | // 2-4 : color resolution = 7
979
- 0x00 | // 5 : gct sort flag = 0
980
- palSize,
981
- ); // 6-8 : gct size
982
-
983
- writeByte(0); // background color index
984
- writeByte(0); // pixel aspect ratio - assume 1:1
985
- }
986
-
987
- // write palette
988
- writePalette(); // global color table
989
-
990
- // Writes Netscape application extension to define repeat count.
991
- if (repeat >= 0) {
992
- writeByte(0x21); // extension introducer
993
- writeByte(0xff); // app extension label
994
- writeByte(11); // block size
995
- writeUTFBytes("NETSCAPE2.0"); // app id + auth code
996
- writeByte(3); // sub-block size
997
- writeByte(1); // loop sub-block id
998
- writeShort(repeat); // loop count (extra iterations, 0=repeat forever)
999
- writeByte(0); // block terminator
1000
- }
1001
- }
1002
-
1003
- // write graphic control extension
1004
- {
1005
- writeByte(0x21); // extension introducer
1006
- writeByte(0xf9); // GCE label
1007
- writeByte(4); // data block size
1008
- var transp;
1009
- var disp;
1010
- if (transparent === null) {
1011
- transp = 0;
1012
- disp = 0; // dispose = no action
1013
- } else {
1014
- transp = 1;
1015
- disp = 2; // force clear if using transparent color
1016
- }
1017
- if (dispose >= 0) {
1018
- disp = dispose & 7; // user override
1019
- }
1020
- disp <<= 2;
1021
- // packed fields
1022
- writeByte(
1023
- 0 | // 1:3 reserved
1024
- disp | // 4:6 disposal
1025
- 0 | // 7 user input - 0 = none
1026
- transp,
1027
- ); // 8 transparency flag
1028
-
1029
- writeShort(delay); // delay x 1/100 sec
1030
- writeByte(transIndex); // transparent color index
1031
- writeByte(0); // block terminator
1032
- }
1033
-
1034
- // write comment
1035
- if (comment !== "") {
1036
- writeByte(0x21); // extension introducer
1037
- writeByte(0xfe); // comment label
1038
- writeByte(comment.length); // Block Size (s)
1039
- writeUTFBytes(comment);
1040
- writeByte(0); // block terminator
1041
- }
1042
-
1043
- // write image descriptor
1044
- {
1045
- writeByte(0x2c); // image separator
1046
- writeShort(0); // image position x,y = 0,0
1047
- writeShort(0);
1048
- writeShort(width); // image size
1049
- writeShort(height);
1050
-
1051
- // packed fields
1052
- if (firstFrame) {
1053
- // no LCT - GCT is used for first (or only) frame
1054
- writeByte(0);
1055
- } else {
1056
- // specify normal LCT
1057
- writeByte(
1058
- 0x80 | // 1 local color table 1=yes
1059
- 0 | // 2 interlace - 0=no
1060
- 0 | // 3 sorted - 0=no
1061
- 0 | // 4-5 reserved
1062
- palSize,
1063
- ); // 6-8 size of color table
1064
- }
1065
- }
1066
-
1067
- if (!firstFrame) {
1068
- writePalette(); // local color table
1069
- }
1070
- colorTab = null;
1071
-
1072
- // encode and write pixel data
1073
- {
1074
- const lzwEncoder = createLzwEncoder({
1075
- width,
1076
- height,
1077
- pixels: indexedPixels,
1078
- colorDepth,
1079
- });
1080
- lzwEncoder.encode({
1081
- writeByte,
1082
- writeBytes,
1083
- });
1084
- }
1085
- firstFrame = false;
1086
- indexedPixels.length = 0;
1087
- return true;
1088
- } catch {
1089
- return false;
1090
- }
1091
- },
1092
-
1093
- /**
1094
- * Adds final trailer to the GIF stream, if you don't call the finish method
1095
- * the GIF asDataUrl will not be valid.
1096
- */
1097
- finish: () => {
1098
- if (finished) return false;
1099
- finished = true;
1100
-
1101
- try {
1102
- writeByte(0x3b); // gif trailer
1103
- return true;
1104
- } catch {
1105
- return false;
1106
- }
1107
- },
1108
-
1109
- readAsBinaryString,
1110
- toDataUrl: () => {
1111
- const gifAsBinaryString = readAsBinaryString();
1112
- return `data:image/gif;base64,${encode64(gifAsBinaryString)}`;
1113
- },
1114
- };
1115
-
1116
- writeUTFBytes("GIF89a"); // header
1117
-
1118
- return encoder;
1119
- };
1120
-
1121
- const encode64 = (input) => {
1122
- let output = "";
1123
- let i = 0;
1124
- let l = input.length;
1125
- let key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
1126
- let chr1;
1127
- let chr2;
1128
- let chr3;
1129
- let enc1;
1130
- let enc2;
1131
- let enc3;
1132
- let enc4;
1133
- while (i < l) {
1134
- chr1 = input.charCodeAt(i++);
1135
- chr2 = input.charCodeAt(i++);
1136
- chr3 = input.charCodeAt(i++);
1137
- enc1 = chr1 >> 2;
1138
- enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
1139
- enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
1140
- enc4 = chr3 & 63;
1141
- if (isNaN(chr2)) enc3 = enc4 = 64;
1142
- else if (isNaN(chr3)) enc4 = 64;
1143
- output =
1144
- output +
1145
- key.charAt(enc1) +
1146
- key.charAt(enc2) +
1147
- key.charAt(enc3) +
1148
- key.charAt(enc4);
1149
- }
1150
- return output;
1151
- };
1152
-
1153
- /*
1154
- on veut pouvoir:
1155
- - mettre le terminal dans un "fake terminal" genre
1156
- avec le style de celui svg
1157
- - enregister une vidéo du terminal
1158
- ça faut que je regarde les apis canvas
1159
-
1160
- https://github.com/welefen/canvas2video/blob/master/src/index.ts
1161
- https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream
1162
- https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder
1163
- https://webglfundamentals.org/webgl/lessons/webgl-tips.html
1164
- https://github.com/xtermjs/xterm.js/blob/master/typings/xterm.d.ts
1165
- */
1166
-
1167
-
1168
- const { Terminal } = window;
1169
- const { FitAddon } = window.FitAddon;
1170
- const { WebglAddon } = window.WebglAddon;
1171
- const { SerializeAddon } = window.SerializeAddon;
1172
-
1173
- const initTerminal = ({
1174
- cols = 80,
1175
- rows = 25,
1176
- paddingLeft = 15,
1177
- paddingRight = 15,
1178
- fontFamily = "SauceCodePro Nerd Font, Source Code Pro, Courier",
1179
- fontSize = 12,
1180
- convertEol = true,
1181
- textInViewport,
1182
- gif,
1183
- video,
1184
- logs,
1185
- }) => {
1186
- if (textInViewport === true) textInViewport = {};
1187
- if (gif === true) gif = {};
1188
- if (video === true) video = {};
1189
- if (!textInViewport && !video && !gif) {
1190
- throw new Error("ansi, video or gif must be enabled");
1191
- }
1192
-
1193
- const log = (...args) => {
1194
- if (logs) {
1195
- console.log(...args);
1196
- }
1197
- };
1198
-
1199
- log("init", { cols, rows, fontFamily, fontSize, convertEol, gif, video });
1200
-
1201
- const cssUrl = new URL("/css/xterm.css", import.meta.url);
1202
- const link = document.createElement("link");
1203
- link.rel = "stylesheet";
1204
- link.href = cssUrl;
1205
- document.head.appendChild(link);
1206
-
1207
- const term = new Terminal({
1208
- convertEol,
1209
- disableStdin: true,
1210
- // cursorBlink: false,
1211
- cursorInactiveStyle: "none",
1212
- cols,
1213
- rows,
1214
- fontFamily,
1215
- fontSize,
1216
- // lineHeight: 18,
1217
- theme: {
1218
- background: "#282c34",
1219
- foreground: "#abb2bf",
1220
- selectionBackground: "#001122",
1221
- selectionForeground: "#777777",
1222
- brightRed: "#B22222",
1223
- brightBlue: "#87CEEB",
1224
- },
1225
- });
1226
- const serializeAddon = new SerializeAddon();
1227
- term.loadAddon(serializeAddon);
1228
- const fitAddon = new FitAddon();
1229
- term.loadAddon(fitAddon);
1230
- const webglAddon = new WebglAddon(
1231
- // we pass true to enable preserveDrawingBuffer
1232
- // it's not actually useful thanks to term.write callback +
1233
- // call on _innerRefresh() before context.drawImage
1234
- // but let's keep it nevertheless
1235
- true,
1236
- );
1237
- term.loadAddon(webglAddon);
1238
- const terminalElement = document.querySelector("#terminal");
1239
- term.open(terminalElement);
1240
- fitAddon.fit();
1241
-
1242
- const canvas = document.querySelector("#canvas");
1243
- if (!canvas) {
1244
- throw new Error('Cannot find <canvas id="canvas"> in the document');
1245
- }
1246
- const xTermCanvasSelector = "#terminal canvas.xterm-link-layer + canvas";
1247
- const xtermCanvas = document.querySelector(xTermCanvasSelector);
1248
- if (!xtermCanvas) {
1249
- throw new Error(`Cannot find xterm canvas (${xTermCanvasSelector})`);
1250
- }
1251
-
1252
- return {
1253
- term,
1254
- startRecording: async () => {
1255
- const context = canvas.getContext("2d", { willReadFrequently: true });
1256
- context.imageSmoothingEnabled = true;
1257
- const headerHeight = 40;
1258
- canvas.width = paddingLeft + xtermCanvas.width + paddingRight;
1259
- canvas.height = headerHeight + xtermCanvas.height;
1260
- {
1261
- drawRectangle(context, {
1262
- x: 0,
1263
- y: 0,
1264
- width: canvas.width,
1265
- height: canvas.height,
1266
- fill: "#282c34",
1267
- stroke: "rgba(255,255,255,0.35)",
1268
- strokeWidth: 10,
1269
- radius: 8,
1270
- });
1271
- drawCircle(context, {
1272
- x: 20,
1273
- y: headerHeight / 2,
1274
- radius: 6,
1275
- fill: "#ff5f57",
1276
- });
1277
- drawCircle(context, {
1278
- x: 40,
1279
- y: headerHeight / 2,
1280
- radius: 6,
1281
- fill: "#febc2e",
1282
- });
1283
- drawCircle(context, {
1284
- x: 60,
1285
- y: headerHeight / 2,
1286
- radius: 6,
1287
- fill: "#28c840",
1288
- });
1289
-
1290
- // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_text
1291
- const text = "Terminal";
1292
- context.font = `${fontSize}px ${fontFamily}`;
1293
- context.textBaseline = "middle";
1294
- context.textAlign = "center";
1295
- // const textSize = context.measureText(text);
1296
- context.fillStyle = "#abb2bf";
1297
- context.fillText(text, canvas.width / 2, headerHeight / 2);
1298
- }
1299
-
1300
- const records = {};
1301
- let writePromise = Promise.resolve();
1302
- const frameCallbackSet = new Set();
1303
- const stopCallbackSet = new Set();
1304
- if (textInViewport) {
1305
- log("start recording text in viewport");
1306
- // https://github.com/xtermjs/xterm.js/issues/3681
1307
- // https://github.com/xtermjs/xterm.js/issues/3681
1308
- // get the first line
1309
- // term.buffer.active.getLine(term.buffer.active.viewportY).translateToString()
1310
- // get the last line
1311
- // term.buffer.active.getLine(term.buffer.active.length -1).translateToString()
1312
- // https://github.com/xtermjs/xterm.js/blob/a7952ff36c60ee6dce9141744b1355a5d582ee39/addons/addon-serialize/src/SerializeAddon.ts
1313
- stopCallbackSet.add(() => {
1314
- const startY = term.buffer.active.viewportY;
1315
- const endY = term.buffer.active.length - 1;
1316
- const range = {
1317
- start: startY,
1318
- end: endY,
1319
- };
1320
- log(`lines in viewport: ${startY}:${endY}`);
1321
- const output = serializeAddon.serialize({
1322
- range,
1323
- });
1324
- log(`text in viewport: ${output}`);
1325
- records.textInViewport = output;
1326
- });
1327
- }
1328
- if (video) {
1329
- log("start recording video");
1330
- const { mimeType = "video/webm;codecs=h264", msAddedAtTheEnd } = video;
1331
- if (!MediaRecorder.isTypeSupported(mimeType)) {
1332
- throw new Error(`MediaRecorder does not support "${mimeType}"`);
1333
- }
1334
- const stream = canvas.captureStream();
1335
- const mediaRecorder = new MediaRecorder(stream, {
1336
- videoBitsPerSecond: 2_500_000,
1337
- mimeType,
1338
- });
1339
- const chunks = [];
1340
- mediaRecorder.ondataavailable = (e) => {
1341
- if (e.data && e.data.size) {
1342
- chunks.push(e.data);
1343
- }
1344
- };
1345
- log("starting media recorder");
1346
- const startPromise = new Promise((resolve, reject) => {
1347
- mediaRecorder.onstart = () => {
1348
- resolve();
1349
- };
1350
- mediaRecorder.onerror = (e) => {
1351
- log("media recorder error");
1352
- reject(e);
1353
- };
1354
- mediaRecorder.start();
1355
- });
1356
- let timeout;
1357
- let hasTimedout = false;
1358
- const MS_ALLOCATED_TO_MEDIA_RECORDER = 2_000;
1359
- await Promise.race([
1360
- startPromise,
1361
- new Promise((resolve) => {
1362
- timeout = setTimeout(() => {
1363
- hasTimedout = true;
1364
- resolve();
1365
- }, MS_ALLOCATED_TO_MEDIA_RECORDER);
1366
- }),
1367
- ]);
1368
- if (hasTimedout) {
1369
- throw new Error(
1370
- `media recorder did not start in less than ${MS_ALLOCATED_TO_MEDIA_RECORDER}ms`,
1371
- );
1372
- }
1373
- clearTimeout(timeout);
1374
- log("media recorder started");
1375
-
1376
- stopCallbackSet.add(async () => {
1377
- if (msAddedAtTheEnd) {
1378
- await new Promise((resolve) => {
1379
- setTimeout(resolve, msAddedAtTheEnd);
1380
- });
1381
- replicateXterm();
1382
- } else {
1383
- replicateXterm();
1384
- }
1385
- await new Promise((resolve) => {
1386
- setTimeout(resolve, 150);
1387
- });
1388
- await new Promise((resolve, reject) => {
1389
- mediaRecorder.onstop = () => {
1390
- resolve();
1391
- };
1392
- mediaRecorder.onerror = (e) => {
1393
- reject(e);
1394
- };
1395
- mediaRecorder.stop();
1396
- });
1397
- const blob = new Blob(chunks, { type: mediaRecorder.mimeType });
1398
- const videoBinaryString = await new Promise((resolve, reject) => {
1399
- const reader = new FileReader();
1400
- reader.onloadend = () => resolve(reader.result);
1401
- reader.onerror = reject;
1402
- reader.readAsBinaryString(blob);
1403
- });
1404
- records.video = videoBinaryString;
1405
- });
1406
- }
1407
- if (gif) {
1408
- log("start recording gif");
1409
- const { repeat = -1, quality, msAddedAtTheEnd } = gif;
1410
- const gifEncoder = createGifEncoder({
1411
- width: canvas.width,
1412
- height: canvas.height,
1413
- repeat: repeat === true ? 0 : repeat === false ? -1 : repeat,
1414
- quality,
1415
- });
1416
- frameCallbackSet.add(({ delay }) => {
1417
- log(`add frame to gif with delay of ${delay}ms`);
1418
- gifEncoder.addFrame(context, { delay });
1419
- });
1420
- stopCallbackSet.add(async () => {
1421
- const now = Date.now();
1422
- drawFrame({
1423
- delay: now - previousTime,
1424
- });
1425
- if (msAddedAtTheEnd) {
1426
- drawFrame({
1427
- delay: now - msAddedAtTheEnd,
1428
- });
1429
- }
1430
- gifEncoder.finish();
1431
- log("gif recording stopped");
1432
- const gifBinaryString = gifEncoder.readAsBinaryString();
1433
- records.gif = gifBinaryString;
1434
- });
1435
- log("gif recorder started");
1436
- }
1437
-
1438
- const startTime = Date.now();
1439
- let previousTime = startTime;
1440
- let isFirstDraw = true;
1441
- const drawFrame = (options) => {
1442
- for (const frameCallback of frameCallbackSet) {
1443
- frameCallback(options);
1444
- }
1445
- };
1446
-
1447
- const replicateXterm = () => {
1448
- context.drawImage(
1449
- xtermCanvas,
1450
- 0,
1451
- 0,
1452
- xtermCanvas.width,
1453
- xtermCanvas.height,
1454
- paddingLeft,
1455
- headerHeight,
1456
- xtermCanvas.width,
1457
- xtermCanvas.height,
1458
- );
1459
- };
1460
-
1461
- replicateXterm();
1462
-
1463
- return {
1464
- writeIntoTerminal: async (data, options = {}) => {
1465
- if (isFirstDraw) {
1466
- isFirstDraw = false;
1467
- drawFrame({ delay: 0 });
1468
- }
1469
- let { delay } = options;
1470
- if (delay === undefined) {
1471
- const now = Date.now();
1472
- delay = now - previousTime;
1473
- }
1474
- writePromise = new Promise((resolve) => {
1475
- log(`write data:`, data);
1476
- term.write(data, () => {
1477
- term._core._renderService._renderDebouncer._innerRefresh();
1478
- replicateXterm();
1479
- drawFrame({ delay });
1480
- resolve();
1481
- });
1482
- });
1483
- await writePromise;
1484
- },
1485
- stopRecording: async () => {
1486
- await writePromise;
1487
- const promises = [];
1488
- for (const stopCallback of stopCallbackSet) {
1489
- promises.push(stopCallback());
1490
- }
1491
- await Promise.all(promises);
1492
- return records;
1493
- },
1494
- };
1495
- },
1496
- };
1497
- };
1498
-
1499
- const drawRectangle = (
1500
- context,
1501
- { x, y, width, height, radius, fill, stroke, strokeWidth },
1502
- ) => {
1503
- context.beginPath();
1504
- {
1505
- context.roundRect(x, y, width, height, [radius]);
1506
- }
1507
- {
1508
- context.fillStyle = fill;
1509
- context.fill();
1510
- }
1511
- {
1512
- context.strokeWidth = strokeWidth;
1513
- context.strokeStyle = stroke;
1514
- context.stroke();
1515
- }
1516
- };
1517
- const drawCircle = (context, { x, y, radius, fill, stroke, borderWidth }) => {
1518
- context.beginPath();
1519
- context.arc(x, y, radius, 0, 2 * Math.PI, false);
1520
- if (fill) {
1521
- context.fillStyle = fill;
1522
- context.fill();
1523
- }
1524
- if (borderWidth) {
1525
- context.lineWidth = 5;
1526
- }
1527
- if (stroke) {
1528
- context.strokeStyle = stroke;
1529
- context.stroke();
1530
- }
1531
- };
1532
-
1533
- export { initTerminal };