@sythos/js_barcode_universal 0.1.0

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.
Files changed (53) hide show
  1. package/LICENSE +215 -0
  2. package/NOTICE.md +106 -0
  3. package/README.md +433 -0
  4. package/bundle/sythos-barcode.esm.js +7998 -0
  5. package/bundle/sythos-barcode.js +7948 -0
  6. package/examples/create.html +731 -0
  7. package/examples/read.html +341 -0
  8. package/licenses/README.md +42 -0
  9. package/licenses/codabar.license +74 -0
  10. package/licenses/code-11.license +69 -0
  11. package/licenses/code-128.license +69 -0
  12. package/licenses/code-39.license +70 -0
  13. package/licenses/code-93.license +71 -0
  14. package/licenses/ean-13.license +70 -0
  15. package/licenses/ean-8.license +70 -0
  16. package/licenses/gs1-128.license +71 -0
  17. package/licenses/isbn.license +76 -0
  18. package/licenses/itf-14.license +69 -0
  19. package/licenses/itf.license +70 -0
  20. package/licenses/msi-plessey.license +72 -0
  21. package/licenses/pharmacode.license +71 -0
  22. package/licenses/qr-code.license +75 -0
  23. package/licenses/upc-a.license +72 -0
  24. package/licenses/upc-e.license +69 -0
  25. package/package.json +89 -0
  26. package/src/core/bit-buffer.js +174 -0
  27. package/src/core/bit-matrix.js +241 -0
  28. package/src/core/errors.js +61 -0
  29. package/src/core/galois-field.js +204 -0
  30. package/src/core/index.js +56 -0
  31. package/src/core/reed-solomon.js +313 -0
  32. package/src/image/binarizer.js +270 -0
  33. package/src/image/grid-sampler.js +164 -0
  34. package/src/image/index.js +40 -0
  35. package/src/image/luminance.js +196 -0
  36. package/src/image/perspective.js +195 -0
  37. package/src/index.js +240 -0
  38. package/src/oned/index.js +89 -0
  39. package/src/oned/patterns.js +384 -0
  40. package/src/oned/reader.js +918 -0
  41. package/src/oned/writers.js +741 -0
  42. package/src/qr/decoder.js +575 -0
  43. package/src/qr/detector.js +630 -0
  44. package/src/qr/encoder.js +958 -0
  45. package/src/qr/index.js +44 -0
  46. package/src/qr/tables.js +737 -0
  47. package/src/render/image-data.js +125 -0
  48. package/src/render/index.js +130 -0
  49. package/src/render/options.js +160 -0
  50. package/src/render/png.js +295 -0
  51. package/src/render/svg.js +120 -0
  52. package/src/render/webgl.js +206 -0
  53. package/src/render/webgpu.js +369 -0
package/README.md ADDED
@@ -0,0 +1,433 @@
1
+ # Sythos Barcode Suite
2
+
3
+ Read and write barcodes in JavaScript.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+ [![Runtime dependencies: 0](https://img.shields.io/badge/runtime%20dependencies-0-brightgreen.svg)](package.json)
7
+
8
+ 100% original code, zero runtime dependencies, MIT. It runs unmodified in Node, in browsers
9
+ (including Safari on iOS) and in web workers. The core requires no canvas, no filesystem and no
10
+ DOM — images go in and come out as plain `{ data, width, height }` RGBA objects, which is exactly
11
+ what an `ImageData` is.
12
+
13
+ **The code is complete and entirely human-readable.** The full source ships. There is no
14
+ WebAssembly, no native addon, no compiled artefact, no binary blob and no minified file anywhere
15
+ in this repository — every tracked file is text you can open and read.
16
+
17
+ That includes the prebuilt bundles. They are *generated*, concatenated and wrapped from `src/` by
18
+ the project's own bundler, but nothing is stripped in the process:
19
+ [`bundle/sythos-barcode.js`](bundle/sythos-barcode.js) runs to roughly 7,900 lines, about a third
20
+ of them comments, averaging a little over 30 characters a line. Open it anywhere and you are
21
+ reading the same annotated code as the source, in the same order — a convenience, not a black box.
22
+
23
+ Don't take that on trust either; it takes one command:
24
+
25
+ ```sh
26
+ awk '{ n += length($0) } END { print "lines:", NR, " avg length:", int(n/NR) }' bundle/sythos-barcode.js
27
+ ```
28
+
29
+ A minified bundle gives you a handful of lines averaging thousands of characters. This one does
30
+ not, and that is the whole point.
31
+
32
+ This is deliberate. A barcode library decides what a scanner believes a label says, so it belongs
33
+ in the category of code you can audit rather than have to trust. Every constant table, every
34
+ check digit and every error-correction step is here in full, with the reasoning next to it.
35
+
36
+ ```js
37
+ import { encode, decode, toSVG, toImageData } from './src/index.js';
38
+
39
+ const matrix = encode('https://example.com', { format: 'qr', ecc: 'M' });
40
+ const svg = toSVG(matrix, { scale: 8 });
41
+
42
+ const found = decode(toImageData(matrix, { scale: 4 }), { formats: ['qr'] });
43
+ console.log(found[0].text); // 'https://example.com'
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Quick start
49
+
50
+ There are four ways in, and none of them needs a build step.
51
+
52
+ ### 1. npm
53
+
54
+ ```sh
55
+ npm install @sythos/js_barcode_universal
56
+ ```
57
+
58
+ `yarn add @sythos/js_barcode_universal` and `pnpm add @sythos/js_barcode_universal` do the same thing. Nothing is installed
59
+ alongside it — there are no runtime dependencies, no postinstall script and no native build. The
60
+ package is plain ESM (`"type": "module"`) and asks for Node 18 or newer.
61
+
62
+ ```js
63
+ import { encode, decode, toSVG, toImageData } from '@sythos/js_barcode_universal';
64
+
65
+ const code = encode('SYT-2026-0042', { format: 'code128' });
66
+
67
+ const svg = toSVG(code, { scale: 2, margin: 10, barHeight: 60 });
68
+ // '<svg xmlns="http://www.w3.org/2000/svg" width="374" height="100" …'
69
+
70
+ const found = decode(toImageData(code, { scale: 4, margin: 10 }), { formats: ['code128'] });
71
+ console.log(found[0].text); // 'SYT-2026-0042'
72
+ ```
73
+
74
+ **Subpath exports** hand you one layer instead of the whole surface, which is what lets a
75
+ tree-shaking bundler drop everything you did not ask for. Importing only the QR writer and only
76
+ the SVG renderer never pulls in the 1D formats, the PNG encoder or the read pipeline:
77
+
78
+ ```js
79
+ import { encodeQR } from '@sythos/js_barcode_universal/qr';
80
+ import { toSVG } from '@sythos/js_barcode_universal/render/svg';
81
+
82
+ const svg = toSVG(encodeQR('https://example.com', { ecc: 'M' }), { scale: 8 });
83
+ // a 25×25 module symbol — 264×264 px at scale 8 with the default 4-module quiet zone
84
+ ```
85
+
86
+ | Subpath | What it exports |
87
+ |---|---|
88
+ | `@sythos/js_barcode_universal` | The whole surface: `encode`, `decode`, every renderer, every error type |
89
+ | `@sythos/js_barcode_universal/core` | `BitMatrix`, `GaloisField`, Reed–Solomon, the error classes |
90
+ | `@sythos/js_barcode_universal/image` | `LuminanceSource`, the binarizers, grid sampling, `PerspectiveTransform` |
91
+ | `@sythos/js_barcode_universal/oned` | The per-format 1D writers (`encodeEAN13`, `encodeCode128`, …) and `decodeOneD` |
92
+ | `@sythos/js_barcode_universal/qr` | `encodeQR`, `decodeQR`, `detectQR`, `detectAndDecodeQR` |
93
+ | `@sythos/js_barcode_universal/render` | Every renderer plus `isWebGL2Available` / `isWebGPUAvailable` |
94
+ | `@sythos/js_barcode_universal/render/svg` | `toSVG`, `toSVGDataURI` |
95
+ | `@sythos/js_barcode_universal/render/png` | `toPNG`, `toPNGDataURI` |
96
+ | `@sythos/js_barcode_universal/render/image-data` | `toImageData`, `toCanvas` |
97
+ | `@sythos/js_barcode_universal/bundle` | The prebuilt ESM bundle, as one file |
98
+ | `@sythos/js_barcode_universal/bundle/iife` | The prebuilt IIFE bundle, for a `<script>` tag |
99
+
100
+ The `unpkg` and `jsdelivr` fields point at the IIFE bundle, so a CDN needs no install at all:
101
+
102
+ ```html
103
+ <script src="https://unpkg.com/@sythos/js_barcode_universal"></script>
104
+ <script src="https://unpkg.com/@sythos/js_barcode_universal@0.1.0"></script>
105
+ <script src="https://cdn.jsdelivr.net/npm/@sythos/js_barcode_universal@0.1.0"></script>
106
+ ```
107
+
108
+ Pin the version for anything you ship; the unpinned form resolves to `latest` and will move under
109
+ you.
110
+
111
+ > **These CDN URLs resolve only once the package has been published to npm.** Until that first
112
+ > publish they 404, and so does `npm install @sythos/js_barcode_universal`. Use the committed
113
+ > [`bundle/sythos-barcode.js`](bundle/sythos-barcode.js) from a checkout in the meantime — it is
114
+ > byte-for-byte the file the CDN will serve.
115
+
116
+ ### 2. A `<script>` tag
117
+
118
+ [`bundle/sythos-barcode.js`](bundle/sythos-barcode.js) is a self-contained IIFE that exposes a
119
+ single global, `SythosBarcode`. It works straight from `file://` — open an HTML file off your
120
+ disk and it runs.
121
+
122
+ ```html
123
+ <script src="bundle/sythos-barcode.js"></script>
124
+ <script>
125
+ var encode = SythosBarcode.encode;
126
+ var toSVGDataURI = SythosBarcode.toSVGDataURI;
127
+
128
+ var img = new Image();
129
+ img.src = toSVGDataURI(encode('https://example.com', { format: 'qr' }), { scale: 8 });
130
+ document.body.appendChild(img);
131
+ </script>
132
+ ```
133
+
134
+ ### 3. ESM bundle
135
+
136
+ [`bundle/sythos-barcode.esm.js`](bundle/sythos-barcode.esm.js) is the same code as a single ES
137
+ module, for `<script type="module">`, a bundler, or Node.
138
+
139
+ ```js
140
+ import { encode, toSVG, toPNG } from './bundle/sythos-barcode.esm.js';
141
+
142
+ const ean = encode('5901234123457', { format: 'ean13' });
143
+
144
+ const svg = toSVG(ean, { scale: 3, margin: 10, barHeight: 80 });
145
+ // '<svg xmlns="http://www.w3.org/2000/svg" width="345" height="141" …'
146
+
147
+ toPNG(ean, { scale: 3, barHeight: 80 }).then((bytes) => {
148
+ // Uint8Array — a 1-bit palette PNG
149
+ });
150
+ ```
151
+
152
+ ### 4. The source directly
153
+
154
+ [`src/index.js`](src/index.js) is plain ESM with JSDoc types and no build step of its own. Import
155
+ it and let your bundler tree-shake; the package is marked side-effect free.
156
+
157
+ ```js
158
+ import { encode, decode, toImageData, listFormats } from './src/index.js';
159
+
160
+ const matrix = encode('https://example.com', { format: 'qr', ecc: 'M' });
161
+ const image = toImageData(matrix, { scale: 4, margin: 4 });
162
+
163
+ const found = decode(image, { formats: ['qr'] });
164
+ // [ { text: 'https://example.com', format: 'qr', version: 2, ecc: 'M', … } ]
165
+ ```
166
+
167
+ Decoding takes anything `ImageData`-shaped, so a canvas, an `OffscreenCanvas`,
168
+ `createImageBitmap`, or an image library's raw buffer all satisfy it without an adapter:
169
+
170
+ ```js
171
+ const ctx = canvas.getContext('2d');
172
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
173
+
174
+ for (const hit of decode(ctx.getImageData(0, 0, canvas.width, canvas.height))) {
175
+ console.log(hit.format, hit.text);
176
+ }
177
+ ```
178
+
179
+ `decode` returns an array, empty when nothing is found. A frame with no barcode is an ordinary
180
+ outcome for a camera loop, not an error, so the common case needs no `try`/`catch`. Use
181
+ `decodeStrict` when absence really is a failure.
182
+
183
+ ---
184
+
185
+ ## Supported formats
186
+
187
+ Generated from `listFormats()`, which reports writing and reading as separate capabilities.
188
+ Writing a symbology is a table lookup; reading one needs a detector that finds it in a
189
+ photograph. The two lists legitimately differ, and saying so here is better than failing at call
190
+ time.
191
+
192
+ | Format | `id` | Kind | Write | Read |
193
+ |---|---|:---:|:---:|:---:|
194
+ | EAN-13 | `ean13` | 1D | ✅ | ✅ |
195
+ | EAN-8 | `ean8` | 1D | ✅ | ✅ |
196
+ | UPC-A | `upca` | 1D | ✅ | ✅ |
197
+ | UPC-E | `upce` | 1D | ✅ | ✅ |
198
+ | ISBN (Bookland) | `isbn` | 1D | ✅ | ✅ [^1] |
199
+ | Code 128 | `code128` | 1D | ✅ | ✅ |
200
+ | GS1-128 | `gs1128` | 1D | ✅ | ✅ [^1] |
201
+ | Code 39 | `code39` | 1D | ✅ | ✅ |
202
+ | Code 93 | `code93` | 1D | ✅ | ✅ |
203
+ | ITF (Interleaved 2 of 5) | `itf` | 1D | ✅ | ✅ |
204
+ | ITF-14 | `itf14` | 1D | ✅ | ✅ [^1] |
205
+ | Codabar | `codabar` | 1D | ✅ | ✅ |
206
+ | Code 11 | `code11` | 1D | ✅ | — |
207
+ | MSI Plessey | `msi` | 1D | ✅ | — |
208
+ | Pharmacode | `pharmacode` | 1D | ✅ | — |
209
+ | QR Code | `qr` | 2D | ✅ | ✅ |
210
+
211
+ Sixteen formats, all writable, thirteen readable. **Code 11, MSI Plessey and Pharmacode are
212
+ write-only** — they encode correctly, but there is no reader for them, and `decode` will never
213
+ return one.
214
+
215
+ [^1]: `gs1128`, `itf14` and `isbn` are sub-variants that share a decoder with their base format, so
216
+ they decode under that base id: a GS1-128 comes back as `code128`, an ITF-14 as `itf`, and an ISBN
217
+ as `ean13`. The payload is intact either way — a GS1-128 *is* a Code 128 with a leading FNC1, an
218
+ ITF-14 *is* an ITF fixed at fourteen digits, and an ISBN barcode *is* an EAN-13 with a 978/979
219
+ prefix. Match on `result.format === 'code128'` rather than `'gs1128'`, or a
220
+ condition on the sub-variant id will silently never fire.
221
+
222
+ ### Not implemented
223
+
224
+ **Data Matrix, PDF417, Aztec, GS1 DataBar and MaxiCode are not implemented** — neither writing
225
+ nor reading. Some scaffolding for them exists in the core (the Galois field code already handles
226
+ the prime field PDF417 needs), but no symbology above is usable today. See [`PLAN.md`](PLAN.md)
227
+ for where they sit.
228
+
229
+ ---
230
+
231
+ ## Live examples
232
+
233
+ Two self-contained pages, each loading the IIFE bundle with a plain `<script>` tag. **Both open
234
+ directly from disk** — double-click the file, no server and no build.
235
+
236
+ ### [`examples/create.html`](examples/create.html)
237
+
238
+ Pick any writable format, type a payload, and watch the symbol redraw as you type; download it as
239
+ PNG or SVG. For QR it adds a **content-type builder** that assembles the payload for you across
240
+ URL, email, phone, SMS, Wi-Fi network, contact card (both vCard and MeCard), geo location and
241
+ calendar event — with correct escaping for each — and shows you the exact string it produced, so
242
+ you can see what a Wi-Fi or vCard QR actually contains. ECC level, version, scale, margin and both
243
+ colours are exposed.
244
+
245
+ ### [`examples/read.html`](examples/read.html)
246
+
247
+ Decode from an image: drop one onto the page, or click to choose a file. It then offers a live
248
+ camera loop that decodes continuously from the video stream.
249
+
250
+ > The file and drag-drop path works anywhere, `file://` included. **The camera needs http(s)**,
251
+ > because `getUserMedia` requires a secure context and refuses to run from `file://`. Serve the
252
+ > folder over localhost for that half; the page detects the situation and says so rather than
253
+ > failing silently.
254
+
255
+ ---
256
+
257
+ ## API summary
258
+
259
+ Two functions carry the whole surface. Everything else is a renderer or a format-specific escape
260
+ hatch.
261
+
262
+ ### Encoding and decoding
263
+
264
+ ```js
265
+ encode(text, options?) → BitMatrix
266
+ ```
267
+
268
+ `options`: `format` (default `'qr'`), `ecc` (`'L'|'M'|'Q'|'H'`), `version` (QR 1–40, auto if
269
+ omitted), `checkDigit`, `fullAscii` (Code 39 extended), `gs1` (emit a leading FNC1).
270
+
271
+ ```js
272
+ encode('5901234123457', { format: 'ean13' })
273
+ encode('ABC-123', { format: 'code39', fullAscii: true, checkDigit: true })
274
+ encode('https://example.com', { format: 'qr', ecc: 'H', version: 7 })
275
+ ```
276
+
277
+ ```js
278
+ decode(image, options?) → Result[]
279
+ decodeStrict(image, options?) → Result // throws NotFoundError instead of returning []
280
+ ```
281
+
282
+ `image` is `{ data, width, height }` with RGBA bytes. `options`: `formats` (restrict the search,
283
+ and go faster), `tryHarder` (retry inverted, default `true`), `binarizer`
284
+ (`'global' | 'hybrid' | 'auto'`). A `Result` carries at least `text` and `format`; QR results also
285
+ carry `bytes`, `version` and `ecc`.
286
+
287
+ ```js
288
+ listFormats() → { id, label, canWrite, canRead, kind }[]
289
+ ```
290
+
291
+ The table above is this function's output. Read it at runtime rather than hard-coding a format
292
+ list — that is how the demo pages build their dropdowns.
293
+
294
+ ### Renderers
295
+
296
+ ```js
297
+ toSVG(matrix, options?) → string // one merged <path>, not a rect per module
298
+ toSVGDataURI(matrix, options?) → string // data: URI for an <img src>
299
+ toImageData(matrix, options?) → { data, width, height }
300
+ toPNG(matrix, options?) → Promise<Uint8Array> // 1-bit palette PNG
301
+ toPNGDataURI(matrix, options?) → Promise<string>
302
+ toCanvas(matrix, canvas, options?) → boolean // 2D context
303
+ renderToCanvasAuto(matrix, canvas, options?) → { backend: 'webgl2' | '2d' | 'none' }
304
+ renderToCanvasAutoAsync(matrix, canvas, options?) → Promise<{ backend: 'webgpu' | 'webgl2' | '2d' | 'none' }>
305
+ ```
306
+
307
+ The two PNG functions are async because they use the platform's deflate — `node:zlib` or
308
+ `CompressionStream` — and fall back to stored blocks where neither exists.
309
+
310
+ `renderToCanvasAuto` is synchronous and therefore cannot reach WebGPU: acquiring an adapter is
311
+ asynchronous, and a synchronous function can never wait for one. Use `renderToCanvasAutoAsync`
312
+ when you want WebGPU in the chain. Both fall through to the 2D context, which always exists.
313
+
314
+ All renderers share the same options:
315
+
316
+ | Option | Default | Meaning |
317
+ |---|---|---|
318
+ | `scale` | `8` | Pixels per module |
319
+ | `margin` | `4` | Quiet-zone modules on every side |
320
+ | `dark` | `'#000000'` | Colour of set modules |
321
+ | `light` | `'#ffffff'` | Colour of clear modules; `'none'` for transparent |
322
+ | `barHeight` | auto | 1D only: total bar height in pixels |
323
+
324
+ Also exported: `BitMatrix`, the error types (`BarcodeError`, `EncodeError`, `NotFoundError`,
325
+ `FormatError`, `ChecksumError`), the per-format writers (`encodeEAN13`, `encodeCode128`, …), the
326
+ QR entry points (`encodeQR`, `decodeQR`, `detectQR`, `detectAndDecodeQR`), the image primitives
327
+ (`LuminanceSource`, `binarize`, `binarizeGlobal`, `binarizeHybrid`), and the capability probes
328
+ `isWebGL2Available` / `isWebGPUAvailable`.
329
+
330
+ ---
331
+
332
+ ## How it works
333
+
334
+ **`BitMatrix` is the interchange type.** Every writer produces one, every reader consumes one,
335
+ every renderer draws one. That single currency is what keeps symbologies and output targets
336
+ independent of each other — adding a format touches no renderer, and adding a renderer touches no
337
+ format. Storage is row-packed into a `Uint32Array`: one allocation, cache-friendly row scans, and
338
+ cheap whole-row operations for the 1D readers.
339
+
340
+ **A set bit is a dark module.** This matches how every specification describes its symbols;
341
+ renderers invert where their medium needs it.
342
+
343
+ **`encode` returns no quiet zone.** The margin is a rendering decision, not an encoding one — how
344
+ much white space a symbol needs depends on where it is going — so the renderers add it and the
345
+ matrix stays the pure symbol. For the same reason, **linear symbols come back exactly one module
346
+ tall**: height carries no information in a 1D barcode, so encoding one would be inventing data.
347
+ The renderer stretches the single row to `barHeight` *before* applying the quiet zone, so the
348
+ margin ends up uniform on all four sides.
349
+
350
+ **The read pipeline** is a straight line, each stage a separate module:
351
+
352
+ ```
353
+ RGBA bytes → luminance → binarize → detect → sample → error-correct → decode
354
+ ```
355
+
356
+ Luminance conversion flattens the image to greyscale. Binarization turns that into a `BitMatrix`,
357
+ either globally or with a hybrid local threshold that survives uneven lighting. Detection locates
358
+ a symbol and its corners in that bit plane. Sampling reads the symbol back onto its module grid
359
+ through a perspective transform, so a photograph taken at an angle still yields a square grid.
360
+ Error correction repairs what the camera lost. Only then is the payload decoded.
361
+
362
+ **Reed–Solomon is generic over the finite field.** The `GaloisField` class is constructed with a
363
+ field order and a primitive polynomial rather than hard-coding GF(256), which is what lets one
364
+ implementation serve QR, and the prime field GF(929) that PDF417 needs. Prime fields are the
365
+ subtle case: in a binary field addition and subtraction are both XOR, so a decoder that inlines
366
+ `^` for field addition passes every binary field and fails only the prime one.
367
+
368
+ ---
369
+
370
+ ## About the GPU path
371
+
372
+ The WebGL2 and WebGPU backends accelerate **drawing** a barcode, not **computing** one. That is
373
+ worth stating plainly, because "GPU barcode generation" naturally suggests the latter.
374
+
375
+ Encoding is sequential integer work: Reed–Solomon polynomial division, mask penalty scoring, bit
376
+ placement along a zig-zag path. Each step depends on the one before it, which is precisely the
377
+ shape a GPU cannot exploit. A complete QR encode takes well under a millisecond on the CPU — less
378
+ time than dispatching a compute shader and reading the result back would cost. Moving it to the
379
+ GPU would make it slower.
380
+
381
+ So encoding stays on the CPU because that is the correct engineering answer, not because
382
+ something is missing. Where the GPU genuinely earns its place is drawing large symbols, or many
383
+ symbols per frame, straight into a canvas without a CPU-side pixel buffer — and it would earn it
384
+ again on the read side, where per-frame greyscale conversion and block statistics over a 4K camera
385
+ image are both the real bottleneck and embarrassingly parallel.
386
+
387
+ ---
388
+
389
+ ## Browser support
390
+
391
+ The syntax floor is **iOS Safari 15**. No `Array.prototype.at`, no top-level `await`, no
392
+ `Object.groupBy`.
393
+
394
+ `OffscreenCanvas`, WebGL2 and WebGPU are feature-detected, never assumed. The 2D canvas path
395
+ always exists, so nothing is unreachable on an older device — `renderToCanvasAuto` degrades to it
396
+ and reports which backend actually drew.
397
+
398
+ ---
399
+
400
+ ## Licence
401
+
402
+ MIT © 2026 Sythos. Every source file carries the header.
403
+
404
+ **The code is 100% original.** No source code and no constant table from any other barcode
405
+ implementation is present, under any licence, permissive or otherwise. The symbologies are
406
+ implemented from published descriptions of the formats — which are systems and facts, not works of
407
+ authorship — and from constant tables generated by this project's own scripts wherever a table is
408
+ derivable rather than arbitrary. There is consequently no upstream licence to carry and no
409
+ co-author to credit.
410
+
411
+ **Trademark is not licence.** QR Code® is a registered trademark of DENSO WAVE; Aztec Code,
412
+ MaxiCode and GS1 DataBar are likewise marks of their owners. A trademark does not restrict
413
+ implementing a symbology, but it does constrain branding — which is why this package is named
414
+ descriptively rather than after any mark.
415
+
416
+ [`LICENSE`](LICENSE) carries the full MIT text plus an informational appendix inventorying the
417
+ specification copyrights, patent history and trademarks that surround these symbologies. None of
418
+ them encumbers this code; the appendix is an engineering inventory, not legal advice.
419
+ [`NOTICE.md`](NOTICE.md) records the origin of the code and how its correctness is verified.
420
+
421
+ ---
422
+
423
+ ## Contributing and roadmap
424
+
425
+ [`PLAN.md`](PLAN.md) is the live status document: what is shipped, what is next, and the ground
426
+ rules — chief among them that no code or constant table from any other barcode implementation
427
+ enters this project, which is what keeps the licence clean.
428
+
429
+ Issues and pull requests are welcome at
430
+ [Sythos/JS_Barcode_Universal](https://github.com/Sythos/JS_Barcode_Universal). A patch that adds a
431
+ symbology should implement it from the published description of the format, generate its tables
432
+ where they are derivable, and come with a symbol that a scanner this project did not write has
433
+ actually read — that last one is the check that matters.