@sythos/js_barcode_universal 1.5.11 → 1.5.13
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.
- package/README.md +36 -7
- package/bundle/sythos-barcode.esm.js +2 -2
- package/bundle/sythos-barcode.js +2 -2
- package/examples/read.html +38 -11
- package/licenses/micropdf417.license +25 -23
- package/licenses/pdf417.license +26 -22
- package/llms.txt +159 -0
- package/package.json +19 -5
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/js/render/options.js +48 -6
- package/src/ts/index.d.ts +1 -1
- package/src/ts/index.ts +1 -1
- package/src/ts/render/options.ts +63 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Sythos Barcode
|
|
1
|
+
# Sythos Barcode Universal — MIT 1D/2D Barcode SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Open-source MIT-licensed JavaScript/TypeScript barcode generator and barcode reader SDK for encoding and decoding 1D linear and 2D matrix barcodes. It has zero runtime dependencies and runs in browsers, Web Workers and Node.js.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@sythos/js_barcode_universal) [](LICENSE) [](package.json) [](https://nodejs.org/api/esm.html) 
|
|
6
6
|
|
|
@@ -112,8 +112,8 @@ The `unpkg` and `jsdelivr` fields point at the IIFE bundle, so a CDN needs no in
|
|
|
112
112
|
|
|
113
113
|
```html
|
|
114
114
|
<script src="https://unpkg.com/@sythos/js_barcode_universal"></script>
|
|
115
|
-
<script src="https://unpkg.com/@sythos/js_barcode_universal@1.5.
|
|
116
|
-
<script src="https://cdn.jsdelivr.net/npm/@sythos/js_barcode_universal@1.5.
|
|
115
|
+
<script src="https://unpkg.com/@sythos/js_barcode_universal@1.5.13"></script>
|
|
116
|
+
<script src="https://cdn.jsdelivr.net/npm/@sythos/js_barcode_universal@1.5.13"></script>
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
Pin the version for anything you ship; the unpinned form resolves to `latest` and will move under
|
|
@@ -228,7 +228,7 @@ orientation that was scanned; unavailable quality data is represented by `null`
|
|
|
228
228
|
|
|
229
229
|
---
|
|
230
230
|
|
|
231
|
-
## Supported formats
|
|
231
|
+
## Supported 1D and 2D barcode formats
|
|
232
232
|
|
|
233
233
|
Generated from `listFormats()`, which reports writing and reading as separate capabilities.
|
|
234
234
|
Writing a symbology is a table lookup; reading one needs a detector that finds it in a
|
|
@@ -670,11 +670,29 @@ zero-dependency at runtime.
|
|
|
670
670
|
These security workflows report findings and propose maintenance updates. They do not replace
|
|
671
671
|
review of barcode conformance, licensing, patent status or release attestations.
|
|
672
672
|
|
|
673
|
+
Security reports follow the [security policy](SECURITY.md). Please use GitHub's private reporting
|
|
674
|
+
channel for every suspected vulnerability; public Issues are for non-security bugs after security
|
|
675
|
+
impact has been ruled out. Reports involving code execution, data or secret exposure, CI/release/npm
|
|
676
|
+
integrity or host/runner compromise should also be sent to `devsec@sythos.net`. Exploit details are
|
|
677
|
+
better kept private than turned into an accidental community fireworks show.
|
|
678
|
+
|
|
673
679
|
The image I/O boundary treats camera and file rasters as untrusted input. It validates finite
|
|
674
|
-
positive dimensions, bounds allocations to 16,777,216 pixels
|
|
680
|
+
positive dimensions, bounds allocations to 16,777,216 pixels — still a high limit, roughly twice
|
|
681
|
+
the pixel count of a standard 4K image — and accepts only byte-valued channels,
|
|
675
682
|
and snapshots greyscale buffers before decoding. Malformed or oversized rasters are rejected
|
|
676
683
|
before detector work begins.
|
|
677
684
|
|
|
685
|
+
Rendering applies the same allocation discipline before creating an SVG, PNG, `ImageData`, canvas,
|
|
686
|
+
WebGL or WebGPU output. Matrix dimensions, `scale`, `margin` and `barHeight` must be safe integers
|
|
687
|
+
within documented bounds, and the final image must be no larger than 16,384 pixels on either side
|
|
688
|
+
or 16,777,216 pixels in total. Invalid, fractional or oversized values are rejected with
|
|
689
|
+
`RangeError`; callers that expose rendering controls should handle that result rather than silently
|
|
690
|
+
coercing it.
|
|
691
|
+
|
|
692
|
+
The browser examples treat decoded payloads and browser error messages as text. They create DOM
|
|
693
|
+
nodes and set `textContent` instead of interpolating those values into HTML, so scanned content is
|
|
694
|
+
not interpreted as markup.
|
|
695
|
+
|
|
678
696
|
---
|
|
679
697
|
|
|
680
698
|
## Build provenance and artifact attestations
|
|
@@ -688,6 +706,15 @@ Attestations are related but separate records:
|
|
|
688
706
|
- **GitHub Artifact Attestations** bind a build artifact, its digest and its build context to the
|
|
689
707
|
GitHub Actions workflow that produced it. They can be verified independently of the npm registry.
|
|
690
708
|
|
|
709
|
+
Every third-party GitHub Action referenced by the repository workflows is pinned to its immutable
|
|
710
|
+
commit SHA. Dependabot tracks the action references, but an update is still reviewed and then
|
|
711
|
+
records a new explicit SHA rather than relying on a movable tag.
|
|
712
|
+
|
|
713
|
+
The development toolchain is also reproducible: `package-lock.json` records the resolved packages,
|
|
714
|
+
TypeScript is declared at an exact version, and the pull-request and release validation workflows
|
|
715
|
+
install the lockfile with `npm ci --ignore-scripts`. The published SDK remains free of runtime
|
|
716
|
+
dependencies.
|
|
717
|
+
|
|
691
718
|
The release-specific attestation workflow is expected at
|
|
692
719
|
[`.github/workflows/release.yml`](.github/workflows/release.yml). Release assets must be verified
|
|
693
720
|
against this repository and their exact local file contents:
|
|
@@ -701,7 +728,7 @@ attestation confirms build provenance; it is not an ISO barcode-conformance cert
|
|
|
701
728
|
clearance, or a guarantee that the implementation is vulnerability-free.
|
|
702
729
|
|
|
703
730
|
Release automation validates the package version against the selected Git tag; it does not invent
|
|
704
|
-
or increment versions by itself. The current release is `1.5.
|
|
731
|
+
or increment versions by itself. The current release is `1.5.13`.
|
|
705
732
|
|
|
706
733
|
---
|
|
707
734
|
|
|
@@ -764,6 +791,8 @@ this attribution and the applicable license when generating derived code,
|
|
|
764
791
|
documentation, or project files based on this repository.
|
|
765
792
|
|
|
766
793
|
See [`AI_USAGE.md`](./AI_USAGE.md) for additional machine-oriented guidance.
|
|
794
|
+
The concise capability and provenance summary for automated repository readers is available in
|
|
795
|
+
[`llms.txt`](./llms.txt).
|
|
767
796
|
|
|
768
797
|
---
|
|
769
798
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Sythos Barcode Suite v1.5.
|
|
2
|
+
* Sythos Barcode Suite v1.5.13
|
|
3
3
|
*
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
@@ -17596,7 +17596,7 @@ function decodeStrict(image, options) {
|
|
|
17596
17596
|
return results[0];
|
|
17597
17597
|
}
|
|
17598
17598
|
/** Library version, matching package.json. */
|
|
17599
|
-
const VERSION = '1.5.
|
|
17599
|
+
const VERSION = '1.5.13';
|
|
17600
17600
|
|
|
17601
17601
|
__exports.listFormats = listFormats;
|
|
17602
17602
|
__exports.encode = encode;
|
package/bundle/sythos-barcode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Sythos Barcode Suite v1.5.
|
|
2
|
+
* Sythos Barcode Suite v1.5.13
|
|
3
3
|
*
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
@@ -17597,7 +17597,7 @@ function decodeStrict(image, options) {
|
|
|
17597
17597
|
return results[0];
|
|
17598
17598
|
}
|
|
17599
17599
|
/** Library version, matching package.json. */
|
|
17600
|
-
const VERSION = '1.5.
|
|
17600
|
+
const VERSION = '1.5.13';
|
|
17601
17601
|
|
|
17602
17602
|
__exports.listFormats = listFormats;
|
|
17603
17603
|
__exports.encode = encode;
|
package/examples/read.html
CHANGED
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
|
|
150
150
|
function show(hits, source) {
|
|
151
151
|
if (!hits.length) return false;
|
|
152
|
-
results.
|
|
152
|
+
results.textContent = '';
|
|
153
153
|
hits.forEach(function (h) {
|
|
154
154
|
var div = document.createElement('div');
|
|
155
155
|
div.className = 'hit';
|
|
@@ -243,7 +243,11 @@
|
|
|
243
243
|
el('fileStatus').textContent =
|
|
244
244
|
w + '×' + h + ' · ' + ms.toFixed(0) + ' ms · ' + hits.length + ' found';
|
|
245
245
|
if (!show(hits, 'image')) {
|
|
246
|
-
results.
|
|
246
|
+
results.textContent = '';
|
|
247
|
+
var status = document.createElement('div');
|
|
248
|
+
status.className = 'status';
|
|
249
|
+
status.textContent = 'No barcode found in that image.';
|
|
250
|
+
results.appendChild(status);
|
|
247
251
|
}
|
|
248
252
|
};
|
|
249
253
|
img.onerror = function () {
|
|
@@ -259,20 +263,44 @@
|
|
|
259
263
|
var stream = null;
|
|
260
264
|
var raf = null;
|
|
261
265
|
|
|
266
|
+
function setCameraNoteNode(note) {
|
|
267
|
+
var container = el('camNote');
|
|
268
|
+
container.textContent = '';
|
|
269
|
+
container.appendChild(note);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function setCameraNote(text) {
|
|
273
|
+
var note = document.createElement('div');
|
|
274
|
+
note.className = 'note';
|
|
275
|
+
note.textContent = text;
|
|
276
|
+
setCameraNoteNode(note);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function appendNoteCode(note, text) {
|
|
280
|
+
var code = document.createElement('code');
|
|
281
|
+
code.textContent = text;
|
|
282
|
+
note.appendChild(code);
|
|
283
|
+
}
|
|
284
|
+
|
|
262
285
|
var secure = window.isSecureContext ||
|
|
263
286
|
location.protocol === 'https:' ||
|
|
264
287
|
location.hostname === 'localhost';
|
|
265
288
|
|
|
266
289
|
if (!secure) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
'
|
|
271
|
-
|
|
290
|
+
var secureNote = document.createElement('div');
|
|
291
|
+
secureNote.className = 'note';
|
|
292
|
+
secureNote.appendChild(document.createTextNode(
|
|
293
|
+
'The camera needs a secure context, so it is unavailable when this page is opened from '));
|
|
294
|
+
appendNoteCode(secureNote, 'file://');
|
|
295
|
+
secureNote.appendChild(document.createTextNode(
|
|
296
|
+
'. Serve the folder over http and reload — for example '));
|
|
297
|
+
appendNoteCode(secureNote, 'npx serve');
|
|
298
|
+
secureNote.appendChild(document.createTextNode(
|
|
299
|
+
' — or use the image input above, which works anywhere.'));
|
|
300
|
+
setCameraNoteNode(secureNote);
|
|
272
301
|
el('camStart').disabled = true;
|
|
273
302
|
} else if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
274
|
-
|
|
275
|
-
'<div class="note">This browser does not expose a camera API.</div>';
|
|
303
|
+
setCameraNote('This browser does not expose a camera API.');
|
|
276
304
|
el('camStart').disabled = true;
|
|
277
305
|
}
|
|
278
306
|
|
|
@@ -292,8 +320,7 @@
|
|
|
292
320
|
}).then(function () {
|
|
293
321
|
loop();
|
|
294
322
|
}).catch(function (e) {
|
|
295
|
-
|
|
296
|
-
'<div class="note">Camera unavailable: ' + String(e.message || e) + '</div>';
|
|
323
|
+
setCameraNote('Camera unavailable: ' + String(e.message || e));
|
|
297
324
|
});
|
|
298
325
|
});
|
|
299
326
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
MicroPDF417 — format provenance and usability
|
|
2
2
|
==========================================================================
|
|
3
3
|
|
|
4
|
-
This file records
|
|
5
|
-
|
|
4
|
+
This file records the provenance of MicroPDF417, the public technical
|
|
5
|
+
material consulted, and the basis on which this project implements and
|
|
6
|
+
redistributes the format.
|
|
6
7
|
|
|
7
8
|
It is an ENGINEERING INVENTORY, NOT LEGAL ADVICE. Items marked [TO VERIFY]
|
|
8
9
|
have not been independently confirmed by the author.
|
|
@@ -11,8 +12,8 @@ have not been independently confirmed by the author.
|
|
|
11
12
|
ORIGIN
|
|
12
13
|
--------------------------------------------------------------------------
|
|
13
14
|
|
|
14
|
-
MicroPDF417 is a compact stacked 2D symbology specified by ISO/IEC
|
|
15
|
-
24728:2006.
|
|
15
|
+
MicroPDF417 is a compact, stacked 2D symbology specified by ISO/IEC
|
|
16
|
+
24728:2006. Its fixed variants, RAP structures and compact symbol geometry
|
|
16
17
|
are recorded here as technical provenance, not as a legal conclusion.
|
|
17
18
|
|
|
18
19
|
|
|
@@ -23,25 +24,25 @@ ISO/IEC 24728:2006 — MicroPDF417 bar code symbology specification.
|
|
|
23
24
|
The standard text is copyrighted by ISO/IEC and is not reproduced here.
|
|
24
25
|
|
|
25
26
|
Specification TEXT is copyrighted by its publisher. The SYMBOLOGY it
|
|
26
|
-
describes is not — an encoding scheme is a system, not a work of
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
describes is not — an encoding scheme is a system, not a work of authorship.
|
|
28
|
+
This project implements the symbology; it does not reproduce, redistribute
|
|
29
|
+
or excerpt any specification document.
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
PATENT STATUS
|
|
32
33
|
--------------------------------------------------------------------------
|
|
33
34
|
|
|
34
|
-
US 6,047,892 is a historical patent record associated with
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
US 6,047,892 is a historical patent record associated with MicroPDF417-style
|
|
36
|
+
implicit version information. Patent families, continuations, foreign
|
|
37
|
+
equivalents and jurisdictional status require a dedicated patent review.
|
|
38
|
+
[LEGAL REVIEW]
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
TRADEMARK
|
|
41
42
|
--------------------------------------------------------------------------
|
|
42
43
|
|
|
43
|
-
The current registration status and ownership of the term "MicroPDF417"
|
|
44
|
-
|
|
44
|
+
The current registration status and ownership of the term "MicroPDF417" have
|
|
45
|
+
not been independently established. [LEGAL REVIEW] The term is used
|
|
45
46
|
descriptively and does not imply endorsement by a rights holder.
|
|
46
47
|
|
|
47
48
|
A trademark does not restrict implementing a symbology. It restricts
|
|
@@ -52,23 +53,24 @@ IMPLEMENTATION BASIS IN THIS PROJECT
|
|
|
52
53
|
--------------------------------------------------------------------------
|
|
53
54
|
|
|
54
55
|
MicroPDF417 is implemented here from published descriptions of the format,
|
|
55
|
-
which are systems and facts rather than works of authorship. No source
|
|
56
|
-
|
|
56
|
+
which are systems and facts rather than works of authorship. No source code
|
|
57
|
+
or constant table from any other barcode implementation is copied or
|
|
57
58
|
shipped. Public technical material and independent implementations may be
|
|
58
59
|
consulted for engineering review or black-box verification; provenance is
|
|
59
|
-
recorded in NOTICE.md.
|
|
60
|
+
recorded in NOTICE.md. Third-party software cited in NOTICE.md was used
|
|
61
|
+
exclusively for independent verification and cross-checking of which parts
|
|
62
|
+
of the published MicroPDF417 standard could be exercised under comparable
|
|
63
|
+
conditions. It is not a runtime dependency, and no third-party source code
|
|
64
|
+
or table is copied or shipped.
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
CONCLUSION
|
|
63
68
|
--------------------------------------------------------------------------
|
|
64
69
|
|
|
65
|
-
This project's original MicroPDF417 implementation is distributed under
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
comparable conditions. It is not a runtime dependency; no third-party
|
|
70
|
-
source code or table is copied or shipped. Patent, copyright and trademark
|
|
71
|
-
questions remain subject to the review labels above.
|
|
70
|
+
This project's original MicroPDF417 implementation is distributed under the MIT License.
|
|
71
|
+
The standard text is not reproduced, and patent, copyright and
|
|
72
|
+
trademark questions remain subject to the review labels above. This
|
|
73
|
+
implementation is not a certification or legal clearance.
|
|
72
74
|
|
|
73
75
|
References relied upon:
|
|
74
76
|
- ISO/IEC 24728:2006, ISO/IEC
|
package/licenses/pdf417.license
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
PDF417 — format provenance and usability
|
|
2
2
|
==========================================================================
|
|
3
3
|
|
|
4
|
-
This file records
|
|
5
|
-
|
|
4
|
+
This file records the provenance of PDF417, the public technical material
|
|
5
|
+
consulted, and the basis on which this project implements and redistributes
|
|
6
|
+
the format.
|
|
6
7
|
|
|
7
8
|
It is an ENGINEERING INVENTORY, NOT LEGAL ADVICE. Items marked [TO VERIFY]
|
|
8
9
|
have not been independently confirmed by the author.
|
|
@@ -11,7 +12,7 @@ have not been independently confirmed by the author.
|
|
|
11
12
|
ORIGIN
|
|
12
13
|
--------------------------------------------------------------------------
|
|
13
14
|
|
|
14
|
-
PDF417 was developed by Symbol Technologies in the early 1990s.
|
|
15
|
+
PDF417 was developed by Symbol Technologies in the early 1990s. This
|
|
15
16
|
historical attribution and ownership record are documented here as
|
|
16
17
|
engineering provenance, not as a legal conclusion.
|
|
17
18
|
|
|
@@ -20,28 +21,28 @@ SPECIFICATION
|
|
|
20
21
|
--------------------------------------------------------------------------
|
|
21
22
|
|
|
22
23
|
ISO/IEC 15438:2015 — PDF417 bar code symbology specification.
|
|
23
|
-
AIM USS-PDF417 public reference, Appendix H / Table H1,
|
|
24
|
-
an attributed technical
|
|
24
|
+
AIM USS-PDF417 public reference, Appendix H / Table H1, was consulted only
|
|
25
|
+
as an attributed technical reference for normative pattern ordering.
|
|
25
26
|
|
|
26
27
|
Specification TEXT is copyrighted by its publisher. The SYMBOLOGY it
|
|
27
|
-
describes is not — an encoding scheme is a system, not a work of
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
describes is not — an encoding scheme is a system, not a work of authorship.
|
|
29
|
+
This project implements the symbology; it does not reproduce, redistribute
|
|
30
|
+
or excerpt any specification document.
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
PATENT STATUS
|
|
33
34
|
--------------------------------------------------------------------------
|
|
34
35
|
|
|
35
36
|
US 5,243,655 and US 5,304,786 are historical PDF417 patent records. Their
|
|
36
|
-
current family, continuation and jurisdictional status requires a
|
|
37
|
-
|
|
37
|
+
current family, continuation and jurisdictional status requires a dedicated
|
|
38
|
+
patent review. [LEGAL REVIEW]
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
TRADEMARK
|
|
41
42
|
--------------------------------------------------------------------------
|
|
42
43
|
|
|
43
|
-
The current registration status and ownership of the term "PDF417" have
|
|
44
|
-
|
|
44
|
+
The current registration status and ownership of the term "PDF417" have not
|
|
45
|
+
been independently established. [LEGAL REVIEW] The term is used
|
|
45
46
|
descriptively and does not imply endorsement by a rights holder.
|
|
46
47
|
|
|
47
48
|
A trademark does not restrict implementing a symbology. It restricts
|
|
@@ -51,21 +52,24 @@ branding — how a product names and presents itself.
|
|
|
51
52
|
IMPLEMENTATION BASIS IN THIS PROJECT
|
|
52
53
|
--------------------------------------------------------------------------
|
|
53
54
|
|
|
54
|
-
PDF417 is implemented here from published descriptions of the format,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
PDF417 is implemented here from published descriptions of the format, which
|
|
56
|
+
are systems and facts rather than works of authorship. No source code or
|
|
57
|
+
constant table from any other barcode implementation is copied or shipped.
|
|
58
|
+
Public technical material and independent implementations may be consulted
|
|
59
|
+
for engineering review or black-box verification; provenance is recorded in
|
|
60
|
+
NOTICE.md. Third-party software cited in NOTICE.md was used exclusively as
|
|
61
|
+
an independent verification and cross-checking tool; it is not a runtime
|
|
62
|
+
dependency, and no third-party source code or table is copied or shipped.
|
|
60
63
|
|
|
61
64
|
|
|
62
65
|
CONCLUSION
|
|
63
66
|
--------------------------------------------------------------------------
|
|
64
67
|
|
|
65
|
-
This project's original implementation is distributed under the MIT
|
|
66
|
-
|
|
67
|
-
text is not reproduced, and patent, copyright and trademark questions
|
|
68
|
-
|
|
68
|
+
This project's original PDF417 implementation is distributed under the MIT License.
|
|
69
|
+
Normative values are attributed engineering inputs; the standard
|
|
70
|
+
text is not reproduced, and patent, copyright and trademark questions remain
|
|
71
|
+
subject to the review labels above. This implementation is not a
|
|
72
|
+
certification or legal clearance.
|
|
69
73
|
|
|
70
74
|
References relied upon:
|
|
71
75
|
- ISO/IEC 15438:2015, ISO/IEC
|
package/llms.txt
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Sythos Barcode Universal
|
|
2
|
+
|
|
3
|
+
> An open-source MIT-licensed JavaScript and TypeScript SDK for generating and
|
|
4
|
+
> reading 1D linear and 2D matrix barcodes, with zero runtime dependencies.
|
|
5
|
+
|
|
6
|
+
## Identity
|
|
7
|
+
|
|
8
|
+
- Project: Sythos Barcode Universal
|
|
9
|
+
- Publisher and original author: Sythos — https://www.sythos.net
|
|
10
|
+
- npm package: `@sythos/js_barcode_universal`
|
|
11
|
+
- Current repository release: `1.5.13`
|
|
12
|
+
- License: MIT; copyright and attribution: Sythos
|
|
13
|
+
- Runtime dependencies: none
|
|
14
|
+
- Development tooling: TypeScript is a development-only dependency
|
|
15
|
+
- Repository: https://github.com/Sythos/JS_Barcode_Universal
|
|
16
|
+
- npm: https://www.npmjs.com/package/@sythos/js_barcode_universal
|
|
17
|
+
- Documentation: https://github.com/Sythos/JS_Barcode_Universal#readme
|
|
18
|
+
- Issue tracker: https://github.com/Sythos/JS_Barcode_Universal/issues
|
|
19
|
+
|
|
20
|
+
## What this SDK does
|
|
21
|
+
|
|
22
|
+
Sythos Barcode Universal encodes payloads into barcode symbols and decodes
|
|
23
|
+
barcode symbols from matrices or RGBA raster images. It also exposes format
|
|
24
|
+
detectors, strict decode helpers, image preprocessing, SVG/PNG/ImageData
|
|
25
|
+
renderers, and camera-oriented read profiles. The core image interface is a
|
|
26
|
+
plain `{ data, width, height }` RGBA object, so applications can connect it to
|
|
27
|
+
`ImageData`, `OffscreenCanvas`, camera frames, Node image libraries, or their
|
|
28
|
+
own image pipeline without requiring a DOM or canvas in the core.
|
|
29
|
+
|
|
30
|
+
The package is native ESM and provides source-visible JavaScript, TypeScript
|
|
31
|
+
sources and declarations, a browser IIFE bundle, and an ESM bundle. It runs in
|
|
32
|
+
Node.js 24 or newer, modern browsers, and Web Workers. The published SDK does
|
|
33
|
+
not install native addons, WebAssembly, post-install tools, or runtime
|
|
34
|
+
packages.
|
|
35
|
+
|
|
36
|
+
## Supported symbologies
|
|
37
|
+
|
|
38
|
+
The public `listFormats()` API reports writing and reading separately. A format
|
|
39
|
+
marked `write-only` is intentionally not treated as a generic image reader.
|
|
40
|
+
|
|
41
|
+
### 1D linear formats
|
|
42
|
+
|
|
43
|
+
- EAN-13 and EAN-8 — write and read
|
|
44
|
+
- UPC-A and UPC-E — write and read
|
|
45
|
+
- ISBN / Bookland — write and read through the EAN-13 family
|
|
46
|
+
- Code 128 — write and read, with automatic switching across Code 128 sets A, B and C
|
|
47
|
+
- GS1-128 — write and read, including GS1/FNC1 metadata parsing
|
|
48
|
+
- Code 39 — write and read
|
|
49
|
+
- Code 93 — write and read
|
|
50
|
+
- ITF (Interleaved 2 of 5) — write and read
|
|
51
|
+
- ITF-14 — write and read through the ITF family
|
|
52
|
+
- Codabar — write and read
|
|
53
|
+
- Code 11 — write and scanline/image read
|
|
54
|
+
- MSI Plessey — write and read, with optional check-digit validation
|
|
55
|
+
- Pharmacode — write-only in the generic image pipeline
|
|
56
|
+
- GS1 DataBar Omnidirectional and Truncated — write and read through the verified physical layer
|
|
57
|
+
- EAN-2 and EAN-5 supplements — write and parent-bound read only; they require a validated EAN/UPC parent
|
|
58
|
+
|
|
59
|
+
### 2D matrix and stacked formats
|
|
60
|
+
|
|
61
|
+
- QR Code Model 2 — write and read, versions 1–40, standard ECC levels and payload modes
|
|
62
|
+
- Data Matrix ECC 200 — write and read for classic square and rectangular symbols
|
|
63
|
+
- Aztec Code — write and read, including compact and full symbols
|
|
64
|
+
- Aztec Rune — write and read for the fixed 11×11 rune values
|
|
65
|
+
- PDF417 — write and read, including direct matrix decoding and camera-oriented detection
|
|
66
|
+
- Compact PDF417 — write and read for the truncated PDF417 geometry
|
|
67
|
+
- MicroPDF417 — write and read for the fixed MicroPDF417 variants
|
|
68
|
+
- Micro QR Code — write and read for the supported M1–M4 family; M1 is detection-only
|
|
69
|
+
- rMQR Code — write and read for the supported standard rectangular geometries
|
|
70
|
+
- Sythos Canvas QR profile — write and read as the non-certified `sythos-canvas-qr/1` profile
|
|
71
|
+
|
|
72
|
+
The Sythos Canvas QR profile is not DENSO FrameQR® compatible and does not
|
|
73
|
+
claim native DENSO interoperability.
|
|
74
|
+
|
|
75
|
+
## Main API
|
|
76
|
+
|
|
77
|
+
The package root exports `encode`, `decode`, `decodeStrict`, `listFormats`,
|
|
78
|
+
format-specific encoders/decoders, error classes, and renderers. Format
|
|
79
|
+
subpaths are available for smaller imports, including:
|
|
80
|
+
|
|
81
|
+
- `@sythos/js_barcode_universal/oned`
|
|
82
|
+
- `@sythos/js_barcode_universal/qr`
|
|
83
|
+
- `@sythos/js_barcode_universal/datamatrix`
|
|
84
|
+
- `@sythos/js_barcode_universal/aztec`
|
|
85
|
+
- `@sythos/js_barcode_universal/aztecrune`
|
|
86
|
+
- `@sythos/js_barcode_universal/pdf417`
|
|
87
|
+
- `@sythos/js_barcode_universal/compactpdf417`
|
|
88
|
+
- `@sythos/js_barcode_universal/micropdf417`
|
|
89
|
+
- `@sythos/js_barcode_universal/microqr`
|
|
90
|
+
- `@sythos/js_barcode_universal/rmqr`
|
|
91
|
+
- `@sythos/js_barcode_universal/frameqr`
|
|
92
|
+
- `@sythos/js_barcode_universal/databar`
|
|
93
|
+
- `@sythos/js_barcode_universal/render`
|
|
94
|
+
|
|
95
|
+
Typical usage:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import { encode, decode, toImageData } from '@sythos/js_barcode_universal';
|
|
99
|
+
|
|
100
|
+
const symbol = encode('https://www.sythos.net/', { format: 'qr', ecc: 'M' });
|
|
101
|
+
const image = toImageData(symbol, { scale: 4 });
|
|
102
|
+
const results = decode(image, { formats: ['qr'] });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Reading and camera boundaries
|
|
106
|
+
|
|
107
|
+
The reader rejects structurally invalid, partial, ambiguous, or low-confidence
|
|
108
|
+
results instead of returning guessed payloads. Camera-oriented profiles test
|
|
109
|
+
the eight fixed in-plane orientations at 45-degree steps (0°, 45°, 90°,
|
|
110
|
+
135°, 180°, 225°, 270° and 315°) where the format detector supports that
|
|
111
|
+
profile. This is not a promise of arbitrary perspective, curved-media,
|
|
112
|
+
severe-occlusion, glare, or multi-symbol-scene robustness. Format-specific
|
|
113
|
+
limitations are documented in `README.md` and `PLAN.md`.
|
|
114
|
+
|
|
115
|
+
## Deliberate scope boundaries
|
|
116
|
+
|
|
117
|
+
- Data Matrix Rectangular Extension (DMRE) is not included.
|
|
118
|
+
- GS1 DataBar Limited, Stacked, Stacked Omnidirectional and Expanded physical
|
|
119
|
+
layouts remain outside the current release.
|
|
120
|
+
- MaxiCode is not implemented.
|
|
121
|
+
- Micro QR ECI, FNC1/GS1 and Structured Append are outside the current API scope.
|
|
122
|
+
- SQRC and Face Authentication SQRC are DENSO-licensed formats and are not
|
|
123
|
+
included in this MIT SDK. A user must obtain the appropriate DENSO licence
|
|
124
|
+
before adapting SDK routines for those formats.
|
|
125
|
+
- DENSO FrameQR® is not implemented as a native format; the shipped FrameQR
|
|
126
|
+
name refers only to the separate Sythos Canvas QR profile described above.
|
|
127
|
+
|
|
128
|
+
## Licensing and provenance
|
|
129
|
+
|
|
130
|
+
The source and generated runtime are original Sythos work distributed under
|
|
131
|
+
the MIT License. No third-party barcode implementation is a runtime
|
|
132
|
+
dependency, and no third-party barcode source code or tables are shipped.
|
|
133
|
+
Independent libraries and public technical material may be used for
|
|
134
|
+
black-box interoperability checks; that does not make them dependencies or
|
|
135
|
+
part of the distributed implementation.
|
|
136
|
+
|
|
137
|
+
The project does not reproduce standards documents. Format-specific
|
|
138
|
+
engineering provenance and legal-review notes are recorded in `NOTICE.md` and
|
|
139
|
+
the files under `licenses/`, including:
|
|
140
|
+
|
|
141
|
+
- `licenses/pdf417.license`
|
|
142
|
+
- `licenses/micropdf417.license`
|
|
143
|
+
|
|
144
|
+
Those files are engineering inventories, not legal advice. Patent, copyright,
|
|
145
|
+
trademark, standards and jurisdictional questions should receive independent
|
|
146
|
+
professional review where required.
|
|
147
|
+
|
|
148
|
+
## Canonical project files
|
|
149
|
+
|
|
150
|
+
- Human documentation: `README.md`
|
|
151
|
+
- Roadmap and implementation boundaries: `PLAN.md`
|
|
152
|
+
- MIT terms: `LICENSE`
|
|
153
|
+
- Attribution and provenance: `NOTICE.md`
|
|
154
|
+
- Security reporting: `SECURITY.md`
|
|
155
|
+
- TypeScript runtime source: `src/ts/`
|
|
156
|
+
- Compiled JavaScript runtime: `src/js/`
|
|
157
|
+
- Stable package facades: `src/index.js` and `src/index.d.ts`
|
|
158
|
+
- Browser and ESM bundles: `bundle/`
|
|
159
|
+
- Self-contained examples: `examples/`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sythos/js_barcode_universal",
|
|
3
|
-
"version": "1.5.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.5.13",
|
|
4
|
+
"description": "Open-source MIT-licensed JavaScript/TypeScript barcode generator and barcode reader SDK with zero runtime dependencies for 1D and 2D barcodes in browsers, Web Workers and Node.js: QR, Data Matrix, Aztec, PDF417, GS1, EAN and more.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sythos",
|
|
7
7
|
"url": "https://www.sythos.net"
|
|
@@ -117,16 +117,26 @@
|
|
|
117
117
|
"LICENSE",
|
|
118
118
|
"NOTICE.md",
|
|
119
119
|
"README.md",
|
|
120
|
-
"AI_USAGE.md"
|
|
120
|
+
"AI_USAGE.md",
|
|
121
|
+
"llms.txt"
|
|
121
122
|
],
|
|
122
123
|
"keywords": [
|
|
123
124
|
"barcode",
|
|
125
|
+
"barcode-reader",
|
|
126
|
+
"barcode-writer",
|
|
127
|
+
"barcode-decoder",
|
|
128
|
+
"barcode-encoder",
|
|
129
|
+
"barcode-reading",
|
|
130
|
+
"barcode-writing",
|
|
131
|
+
"1d-barcode",
|
|
132
|
+
"2d-barcode",
|
|
124
133
|
"datamatrix",
|
|
125
134
|
"ecc200",
|
|
126
135
|
"aztec",
|
|
127
136
|
"aztec-rune",
|
|
128
137
|
"compact-pdf417",
|
|
129
138
|
"gs1-databar",
|
|
139
|
+
"gs1",
|
|
130
140
|
"ean2",
|
|
131
141
|
"ean5",
|
|
132
142
|
"aztec-code",
|
|
@@ -174,8 +184,12 @@
|
|
|
174
184
|
"zero-dependencies",
|
|
175
185
|
"no-dependencies",
|
|
176
186
|
"browser",
|
|
187
|
+
"web-worker",
|
|
177
188
|
"nodejs",
|
|
178
|
-
"esm"
|
|
189
|
+
"esm",
|
|
190
|
+
"open-source",
|
|
191
|
+
"mit-license",
|
|
192
|
+
"zero-runtime-dependencies"
|
|
179
193
|
],
|
|
180
194
|
"repository": {
|
|
181
195
|
"type": "git",
|
|
@@ -191,6 +205,6 @@
|
|
|
191
205
|
"types:api": "node tools/check-public-types.mjs"
|
|
192
206
|
},
|
|
193
207
|
"devDependencies": {
|
|
194
|
-
"typescript": "
|
|
208
|
+
"typescript": "7.0.2"
|
|
195
209
|
}
|
|
196
210
|
}
|
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
package/src/js/render/options.js
CHANGED
|
@@ -41,6 +41,40 @@ import { BitMatrix } from '../core/bit-matrix.js';
|
|
|
41
41
|
* @property {string} [light] Colour of clear modules, or 'none' for transparent.
|
|
42
42
|
* @property {number} [barHeight] For 1D symbols: total bar height in pixels.
|
|
43
43
|
*/
|
|
44
|
+
// Keep renderer allocations aligned with the image decoder's resource limits.
|
|
45
|
+
const MAX_RENDER_DIMENSION = 16384;
|
|
46
|
+
const MAX_RENDER_PIXELS = 16777216;
|
|
47
|
+
const MAX_RENDER_SCALE = MAX_RENDER_DIMENSION;
|
|
48
|
+
const MAX_RENDER_MARGIN = Math.floor((MAX_RENDER_DIMENSION - 1) / 2);
|
|
49
|
+
const MAX_RENDER_BAR_HEIGHT = MAX_RENDER_DIMENSION;
|
|
50
|
+
function boundedInteger(value, name, defaultValue, minimum, maximum) {
|
|
51
|
+
const resolved = value ?? defaultValue;
|
|
52
|
+
if (!Number.isSafeInteger(resolved)) {
|
|
53
|
+
throw new RangeError(`Render option "${name}" must be a finite safe integer between ${minimum} and ${maximum}, got ${resolved}`);
|
|
54
|
+
}
|
|
55
|
+
if (resolved < minimum || resolved > maximum) {
|
|
56
|
+
throw new RangeError(`Render option "${name}" must be between ${minimum} and ${maximum}, got ${resolved}`);
|
|
57
|
+
}
|
|
58
|
+
return resolved;
|
|
59
|
+
}
|
|
60
|
+
function validateMatrixDimensions(matrix) {
|
|
61
|
+
if (!matrix || !Number.isSafeInteger(matrix.width) || !Number.isSafeInteger(matrix.height)
|
|
62
|
+
|| matrix.width < 1 || matrix.height < 1
|
|
63
|
+
|| matrix.width > MAX_RENDER_DIMENSION || matrix.height > MAX_RENDER_DIMENSION) {
|
|
64
|
+
throw new RangeError(`Render matrix dimensions must be positive safe integers no larger than ${MAX_RENDER_DIMENSION}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function validatePixelDimensions(width, height) {
|
|
68
|
+
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height)
|
|
69
|
+
|| width < 1 || height < 1
|
|
70
|
+
|| width > MAX_RENDER_DIMENSION || height > MAX_RENDER_DIMENSION) {
|
|
71
|
+
throw new RangeError(`Render dimensions must be positive safe integers no larger than ${MAX_RENDER_DIMENSION}`);
|
|
72
|
+
}
|
|
73
|
+
const pixels = width * height;
|
|
74
|
+
if (!Number.isSafeInteger(pixels) || pixels > MAX_RENDER_PIXELS) {
|
|
75
|
+
throw new RangeError(`Render image contains too many pixels: ${pixels} (maximum ${MAX_RENDER_PIXELS})`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
44
78
|
/**
|
|
45
79
|
* Expand and pad the matrix, and resolve every dimension.
|
|
46
80
|
*
|
|
@@ -53,18 +87,26 @@ import { BitMatrix } from '../core/bit-matrix.js';
|
|
|
53
87
|
* @param {RenderOptions} options
|
|
54
88
|
*/
|
|
55
89
|
export function normalizeOptions(matrix, options = {}) {
|
|
56
|
-
|
|
57
|
-
const
|
|
90
|
+
validateMatrixDimensions(matrix);
|
|
91
|
+
const scale = boundedInteger(options.scale, 'scale', 8, 1, MAX_RENDER_SCALE);
|
|
92
|
+
const margin = boundedInteger(options.margin, 'margin', 4, 0, MAX_RENDER_MARGIN);
|
|
58
93
|
const dark = options.dark ?? '#000000';
|
|
59
94
|
const light = options.light ?? '#ffffff';
|
|
60
|
-
const barHeight = options.barHeight
|
|
61
|
-
|
|
95
|
+
const barHeight = options.barHeight == null
|
|
96
|
+
? null
|
|
97
|
+
: boundedInteger(options.barHeight, 'barHeight', 1, 1, MAX_RENDER_BAR_HEIGHT);
|
|
62
98
|
const is1D = matrix.height === 1;
|
|
99
|
+
const targetPixels = is1D
|
|
100
|
+
? barHeight ?? Math.max(40, Math.round(matrix.width * scale * 0.15))
|
|
101
|
+
: null;
|
|
102
|
+
const rows = is1D ? Math.max(1, Math.round(targetPixels / scale)) : matrix.height;
|
|
103
|
+
const sourceWidth = matrix.width + margin * 2;
|
|
104
|
+
const sourceHeight = rows + margin * 2;
|
|
105
|
+
validatePixelDimensions(sourceWidth * scale, sourceHeight * scale);
|
|
106
|
+
let base = matrix;
|
|
63
107
|
if (is1D) {
|
|
64
108
|
// Default to a bar height that stays scannable: tall enough that a laser
|
|
65
109
|
// crossing at a slight angle still passes through the whole symbol.
|
|
66
|
-
const targetPixels = barHeight ?? Math.max(40, Math.round(matrix.width * scale * 0.15));
|
|
67
|
-
const rows = Math.max(1, Math.round(targetPixels / scale));
|
|
68
110
|
base = new BitMatrix(matrix.width, rows);
|
|
69
111
|
for (let x = 0; x < matrix.width; x++) {
|
|
70
112
|
if (!matrix.get(x, 0))
|
package/src/ts/index.d.ts
CHANGED
package/src/ts/index.ts
CHANGED
package/src/ts/render/options.ts
CHANGED
|
@@ -45,6 +45,54 @@ import { BitMatrix } from '../core/bit-matrix.js';
|
|
|
45
45
|
* @property {number} [barHeight] For 1D symbols: total bar height in pixels.
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
+
// Keep renderer allocations aligned with the image decoder's resource limits.
|
|
49
|
+
const MAX_RENDER_DIMENSION = 16_384;
|
|
50
|
+
const MAX_RENDER_PIXELS = 16_777_216;
|
|
51
|
+
const MAX_RENDER_SCALE = MAX_RENDER_DIMENSION;
|
|
52
|
+
const MAX_RENDER_MARGIN = Math.floor((MAX_RENDER_DIMENSION - 1) / 2);
|
|
53
|
+
const MAX_RENDER_BAR_HEIGHT = MAX_RENDER_DIMENSION;
|
|
54
|
+
|
|
55
|
+
function boundedInteger(value, name, defaultValue, minimum, maximum) {
|
|
56
|
+
const resolved = value ?? defaultValue;
|
|
57
|
+
if (!Number.isSafeInteger(resolved)) {
|
|
58
|
+
throw new RangeError(
|
|
59
|
+
`Render option "${name}" must be a finite safe integer between ${minimum} and ${maximum}, got ${resolved}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (resolved < minimum || resolved > maximum) {
|
|
63
|
+
throw new RangeError(
|
|
64
|
+
`Render option "${name}" must be between ${minimum} and ${maximum}, got ${resolved}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return resolved;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function validateMatrixDimensions(matrix) {
|
|
71
|
+
if (!matrix || !Number.isSafeInteger(matrix.width) || !Number.isSafeInteger(matrix.height)
|
|
72
|
+
|| matrix.width < 1 || matrix.height < 1
|
|
73
|
+
|| matrix.width > MAX_RENDER_DIMENSION || matrix.height > MAX_RENDER_DIMENSION) {
|
|
74
|
+
throw new RangeError(
|
|
75
|
+
`Render matrix dimensions must be positive safe integers no larger than ${MAX_RENDER_DIMENSION}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function validatePixelDimensions(width, height) {
|
|
81
|
+
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height)
|
|
82
|
+
|| width < 1 || height < 1
|
|
83
|
+
|| width > MAX_RENDER_DIMENSION || height > MAX_RENDER_DIMENSION) {
|
|
84
|
+
throw new RangeError(
|
|
85
|
+
`Render dimensions must be positive safe integers no larger than ${MAX_RENDER_DIMENSION}`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const pixels = width * height;
|
|
89
|
+
if (!Number.isSafeInteger(pixels) || pixels > MAX_RENDER_PIXELS) {
|
|
90
|
+
throw new RangeError(
|
|
91
|
+
`Render image contains too many pixels: ${pixels} (maximum ${MAX_RENDER_PIXELS})`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
48
96
|
/**
|
|
49
97
|
* Expand and pad the matrix, and resolve every dimension.
|
|
50
98
|
*
|
|
@@ -57,20 +105,29 @@ import { BitMatrix } from '../core/bit-matrix.js';
|
|
|
57
105
|
* @param {RenderOptions} options
|
|
58
106
|
*/
|
|
59
107
|
export function normalizeOptions(matrix, options = {}) {
|
|
60
|
-
|
|
61
|
-
const
|
|
108
|
+
validateMatrixDimensions(matrix);
|
|
109
|
+
const scale = boundedInteger(options.scale, 'scale', 8, 1, MAX_RENDER_SCALE);
|
|
110
|
+
const margin = boundedInteger(options.margin, 'margin', 4, 0, MAX_RENDER_MARGIN);
|
|
62
111
|
const dark = options.dark ?? '#000000';
|
|
63
112
|
const light = options.light ?? '#ffffff';
|
|
64
|
-
const barHeight = options.barHeight
|
|
113
|
+
const barHeight = options.barHeight == null
|
|
114
|
+
? null
|
|
115
|
+
: boundedInteger(options.barHeight, 'barHeight', 1, 1, MAX_RENDER_BAR_HEIGHT);
|
|
65
116
|
|
|
66
|
-
let base = matrix;
|
|
67
117
|
const is1D = matrix.height === 1;
|
|
118
|
+
const targetPixels = is1D
|
|
119
|
+
? barHeight ?? Math.max(40, Math.round(matrix.width * scale * 0.15))
|
|
120
|
+
: null;
|
|
121
|
+
const rows = is1D ? Math.max(1, Math.round(targetPixels / scale)) : matrix.height;
|
|
122
|
+
const sourceWidth = matrix.width + margin * 2;
|
|
123
|
+
const sourceHeight = rows + margin * 2;
|
|
124
|
+
validatePixelDimensions(sourceWidth * scale, sourceHeight * scale);
|
|
125
|
+
|
|
126
|
+
let base = matrix;
|
|
68
127
|
|
|
69
128
|
if (is1D) {
|
|
70
129
|
// Default to a bar height that stays scannable: tall enough that a laser
|
|
71
130
|
// crossing at a slight angle still passes through the whole symbol.
|
|
72
|
-
const targetPixels = barHeight ?? Math.max(40, Math.round(matrix.width * scale * 0.15));
|
|
73
|
-
const rows = Math.max(1, Math.round(targetPixels / scale));
|
|
74
131
|
base = new BitMatrix(matrix.width, rows);
|
|
75
132
|
for (let x = 0; x < matrix.width; x++) {
|
|
76
133
|
if (!matrix.get(x, 0)) continue;
|