@sythos/js_barcode_universal 1.5.8 → 1.5.9

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 (179) hide show
  1. package/LICENSE +5 -4
  2. package/NOTICE.md +2 -2
  3. package/README.md +17 -13
  4. package/bundle/sythos-barcode.esm.js +11658 -11244
  5. package/bundle/sythos-barcode.js +11658 -11244
  6. package/package.json +10 -3
  7. package/src/index.d.ts +1 -1
  8. package/src/index.js +508 -516
  9. package/src/js/aztec/decoder.js +208 -199
  10. package/src/js/aztec/detector.js +153 -126
  11. package/src/js/aztec/encoder.js +172 -153
  12. package/src/js/aztec/high-level.js +106 -101
  13. package/src/js/aztec/index.js +1 -12
  14. package/src/js/aztec/tables.js +106 -120
  15. package/src/js/aztecrune/decoder.js +76 -85
  16. package/src/js/aztecrune/detector.js +107 -93
  17. package/src/js/aztecrune/encoder.js +50 -68
  18. package/src/js/aztecrune/index.js +1 -16
  19. package/src/js/aztecrune/tables.js +59 -54
  20. package/src/js/compactpdf417/decoder.js +69 -74
  21. package/src/js/compactpdf417/detector.js +74 -75
  22. package/src/js/compactpdf417/encoder.js +68 -81
  23. package/src/js/compactpdf417/index.js +1 -13
  24. package/src/js/compactpdf417/tables.js +71 -80
  25. package/src/js/core/bit-buffer.js +106 -122
  26. package/src/js/core/bit-matrix.js +196 -194
  27. package/src/js/core/errors.js +13 -15
  28. package/src/js/core/galois-field.js +119 -133
  29. package/src/js/core/index.js +2 -19
  30. package/src/js/core/reed-solomon.js +195 -204
  31. package/src/js/databar/codec.js +93 -108
  32. package/src/js/databar/decoder.js +149 -140
  33. package/src/js/databar/encoder.js +47 -55
  34. package/src/js/databar/gs1.js +122 -123
  35. package/src/js/databar/index.js +4 -36
  36. package/src/js/databar/patterns.js +81 -85
  37. package/src/js/databar/tables.js +51 -52
  38. package/src/js/datamatrix/decoder.js +216 -182
  39. package/src/js/datamatrix/detector.js +161 -132
  40. package/src/js/datamatrix/encoder.js +192 -133
  41. package/src/js/datamatrix/index.js +1 -9
  42. package/src/js/datamatrix/tables.js +68 -69
  43. package/src/js/frameqr/decoder.js +102 -125
  44. package/src/js/frameqr/detector.js +101 -94
  45. package/src/js/frameqr/encoder.js +67 -80
  46. package/src/js/frameqr/index.js +1 -10
  47. package/src/js/frameqr/tables.js +145 -163
  48. package/src/js/image/binarizer.js +146 -162
  49. package/src/js/image/grid-sampler.js +63 -79
  50. package/src/js/image/index.js +0 -2
  51. package/src/js/image/luminance.js +129 -140
  52. package/src/js/image/perspective.js +112 -149
  53. package/src/js/micropdf417/compaction.js +64 -65
  54. package/src/js/micropdf417/decoder.js +106 -109
  55. package/src/js/micropdf417/detector.js +73 -70
  56. package/src/js/micropdf417/encoder.js +129 -154
  57. package/src/js/micropdf417/error-correction.js +6 -11
  58. package/src/js/micropdf417/index.js +2 -16
  59. package/src/js/micropdf417/tables.js +112 -99
  60. package/src/js/microqr/decoder.js +177 -182
  61. package/src/js/microqr/detector.js +240 -256
  62. package/src/js/microqr/encoder.js +239 -194
  63. package/src/js/microqr/index.js +0 -2
  64. package/src/js/microqr/tables.js +208 -200
  65. package/src/js/oned/addons.js +167 -191
  66. package/src/js/oned/index.js +27 -58
  67. package/src/js/oned/patterns.js +194 -213
  68. package/src/js/oned/reader.js +1003 -984
  69. package/src/js/oned/writers.js +411 -466
  70. package/src/js/pdf417/compaction.js +315 -222
  71. package/src/js/pdf417/decoder.js +71 -36
  72. package/src/js/pdf417/detector.js +377 -361
  73. package/src/js/pdf417/encoder.js +57 -46
  74. package/src/js/pdf417/error-correction.js +5 -8
  75. package/src/js/pdf417/tables.js +248 -250
  76. package/src/js/qr/decoder.js +311 -347
  77. package/src/js/qr/detector.js +378 -395
  78. package/src/js/qr/encoder.js +514 -599
  79. package/src/js/qr/index.js +0 -2
  80. package/src/js/qr/tables.js +375 -422
  81. package/src/js/render/image-data.js +57 -62
  82. package/src/js/render/index.js +21 -23
  83. package/src/js/render/options.js +82 -90
  84. package/src/js/render/png.js +144 -169
  85. package/src/js/render/svg.js +41 -44
  86. package/src/js/render/webgl.js +103 -109
  87. package/src/js/render/webgpu.js +205 -217
  88. package/src/js/rmqr/decoder.js +161 -53
  89. package/src/js/rmqr/detector.js +73 -41
  90. package/src/js/rmqr/encoder.js +253 -104
  91. package/src/js/rmqr/index.js +1 -5
  92. package/src/js/rmqr/tables.js +108 -85
  93. package/src/ts/aztec/decoder.ts +317 -0
  94. package/src/ts/aztec/detector.ts +224 -0
  95. package/src/ts/aztec/encoder.ts +257 -0
  96. package/src/ts/aztec/high-level.ts +211 -0
  97. package/src/ts/aztec/index.ts +45 -0
  98. package/src/ts/aztec/tables.ts +210 -0
  99. package/src/ts/aztecrune/decoder.ts +155 -0
  100. package/src/ts/aztecrune/detector.ts +166 -0
  101. package/src/ts/aztecrune/encoder.ts +121 -0
  102. package/src/ts/aztecrune/index.ts +49 -0
  103. package/src/ts/aztecrune/tables.ts +137 -0
  104. package/src/ts/compactpdf417/decoder.ts +128 -0
  105. package/src/ts/compactpdf417/detector.ts +139 -0
  106. package/src/ts/compactpdf417/encoder.ts +140 -0
  107. package/src/ts/compactpdf417/index.ts +17 -0
  108. package/src/ts/compactpdf417/tables.ts +173 -0
  109. package/src/ts/core/bit-buffer.ts +174 -0
  110. package/src/ts/core/bit-matrix.ts +241 -0
  111. package/src/ts/core/errors.ts +61 -0
  112. package/src/ts/core/galois-field.ts +207 -0
  113. package/src/ts/core/index.ts +56 -0
  114. package/src/ts/core/reed-solomon.ts +327 -0
  115. package/src/ts/databar/codec.ts +181 -0
  116. package/src/ts/databar/decoder.ts +215 -0
  117. package/src/ts/databar/encoder.ts +96 -0
  118. package/src/ts/databar/gs1.ts +177 -0
  119. package/src/ts/databar/index.ts +68 -0
  120. package/src/ts/databar/patterns.ts +143 -0
  121. package/src/ts/databar/tables.ts +124 -0
  122. package/src/ts/datamatrix/decoder.ts +262 -0
  123. package/src/ts/datamatrix/detector.ts +225 -0
  124. package/src/ts/datamatrix/encoder.ts +191 -0
  125. package/src/ts/datamatrix/index.ts +42 -0
  126. package/src/ts/datamatrix/tables.ts +123 -0
  127. package/src/ts/frameqr/decoder.ts +239 -0
  128. package/src/ts/frameqr/detector.ts +192 -0
  129. package/src/ts/frameqr/encoder.ts +156 -0
  130. package/src/ts/frameqr/index.ts +42 -0
  131. package/src/ts/frameqr/tables.ts +270 -0
  132. package/src/ts/image/binarizer.ts +270 -0
  133. package/src/ts/image/grid-sampler.ts +164 -0
  134. package/src/ts/image/index.ts +40 -0
  135. package/src/ts/image/luminance.ts +196 -0
  136. package/src/ts/image/perspective.ts +195 -0
  137. package/src/ts/index.d.ts +1 -1
  138. package/src/ts/index.ts +790 -0
  139. package/src/ts/micropdf417/compaction.ts +116 -0
  140. package/src/ts/micropdf417/decoder.ts +183 -0
  141. package/src/ts/micropdf417/detector.ts +149 -0
  142. package/src/ts/micropdf417/encoder.ts +209 -0
  143. package/src/ts/micropdf417/error-correction.ts +55 -0
  144. package/src/ts/micropdf417/index.ts +49 -0
  145. package/src/ts/micropdf417/tables.ts +184 -0
  146. package/src/ts/microqr/decoder.ts +245 -0
  147. package/src/ts/microqr/detector.ts +355 -0
  148. package/src/ts/microqr/encoder.ts +269 -0
  149. package/src/ts/microqr/index.ts +36 -0
  150. package/src/ts/microqr/tables.ts +316 -0
  151. package/src/ts/oned/addons.ts +420 -0
  152. package/src/ts/oned/index.ts +106 -0
  153. package/src/ts/oned/patterns.ts +384 -0
  154. package/src/ts/oned/reader.ts +1364 -0
  155. package/src/ts/oned/writers.ts +746 -0
  156. package/src/ts/pdf417/compaction.ts +298 -0
  157. package/src/ts/pdf417/decoder.ts +75 -0
  158. package/src/ts/pdf417/detector.ts +468 -0
  159. package/src/ts/pdf417/encoder.ts +91 -0
  160. package/src/ts/pdf417/error-correction.ts +47 -0
  161. package/src/ts/pdf417/index.ts +6 -0
  162. package/src/ts/pdf417/tables.ts +317 -0
  163. package/src/ts/qr/decoder.ts +575 -0
  164. package/src/ts/qr/detector.ts +630 -0
  165. package/src/ts/qr/encoder.ts +958 -0
  166. package/src/ts/qr/index.ts +44 -0
  167. package/src/ts/qr/tables.ts +737 -0
  168. package/src/ts/render/image-data.ts +125 -0
  169. package/src/ts/render/index.ts +130 -0
  170. package/src/ts/render/options.ts +160 -0
  171. package/src/ts/render/png.ts +295 -0
  172. package/src/ts/render/svg.ts +120 -0
  173. package/src/ts/render/webgl.ts +206 -0
  174. package/src/ts/render/webgpu.ts +369 -0
  175. package/src/ts/rmqr/decoder.ts +101 -0
  176. package/src/ts/rmqr/detector.ts +90 -0
  177. package/src/ts/rmqr/encoder.ts +172 -0
  178. package/src/ts/rmqr/index.ts +37 -0
  179. package/src/ts/rmqr/tables.ts +154 -0
@@ -27,7 +27,6 @@
27
27
  *
28
28
  * Original work. No code from any other barcode implementation.
29
29
  */
30
-
31
30
  /**
32
31
  * WebGPU drawing.
33
32
  *
@@ -45,9 +44,7 @@
45
44
  *
46
45
  * @module render/webgpu
47
46
  */
48
-
49
47
  import { normalizeOptions, parseColor } from './options.js';
50
-
51
48
  /**
52
49
  * Vertex and fragment stages in one module, mirroring the WebGL2 pair.
53
50
  *
@@ -92,7 +89,6 @@ fn fragmentMain(@location(0) quadUV : vec2<f32>) -> @location(0) vec4<f32> {
92
89
  return select(style.light, style.dark, v > 0.5);
93
90
  }
94
91
  `;
95
-
96
92
  /**
97
93
  * The adapter and device are per-page, not per-barcode.
98
94
  *
@@ -105,7 +101,6 @@ fn fragmentMain(@location(0) quadUV : vec2<f32>) -> @location(0) vec4<f32> {
105
101
  * @type {Promise<any> | null}
106
102
  */
107
103
  let sharedDevice = null;
108
-
109
104
  /**
110
105
  * Get the shared device, requesting one on first use.
111
106
  *
@@ -114,43 +109,43 @@ let sharedDevice = null;
114
109
  * @returns {Promise<any>} The device, or null.
115
110
  */
116
111
  function acquireDevice() {
117
- if (sharedDevice) return sharedDevice;
118
-
119
- // Hoisted so the `lost` handler below can compare against this exact
120
- // promise, and never clear a newer one that has replaced it.
121
- function forget() {
122
- if (sharedDevice === pending) sharedDevice = null;
123
- }
124
-
125
- const pending = (async () => {
126
- try {
127
- if (typeof navigator === 'undefined' || !navigator.gpu) return null;
128
- const adapter = await navigator.gpu.requestAdapter();
129
- if (!adapter) {
130
- forget();
131
- return null;
132
- }
133
- const device = await adapter.requestDevice();
134
- if (!device) {
135
- forget();
136
- return null;
137
- }
138
- // A lost device can never be revived, so drop it and let the next
139
- // render ask for a fresh one instead of failing forever.
140
- if (device.lost && typeof device.lost.then === 'function') {
141
- device.lost.then(forget, forget);
142
- }
143
- return device;
144
- } catch {
145
- forget();
146
- return null;
112
+ if (sharedDevice)
113
+ return sharedDevice;
114
+ // Hoisted so the `lost` handler below can compare against this exact
115
+ // promise, and never clear a newer one that has replaced it.
116
+ function forget() {
117
+ if (sharedDevice === pending)
118
+ sharedDevice = null;
147
119
  }
148
- })();
149
-
150
- sharedDevice = pending;
151
- return pending;
120
+ const pending = (async () => {
121
+ try {
122
+ if (typeof navigator === 'undefined' || !navigator.gpu)
123
+ return null;
124
+ const adapter = await navigator.gpu.requestAdapter();
125
+ if (!adapter) {
126
+ forget();
127
+ return null;
128
+ }
129
+ const device = await adapter.requestDevice();
130
+ if (!device) {
131
+ forget();
132
+ return null;
133
+ }
134
+ // A lost device can never be revived, so drop it and let the next
135
+ // render ask for a fresh one instead of failing forever.
136
+ if (device.lost && typeof device.lost.then === 'function') {
137
+ device.lost.then(forget, forget);
138
+ }
139
+ return device;
140
+ }
141
+ catch {
142
+ forget();
143
+ return null;
144
+ }
145
+ })();
146
+ sharedDevice = pending;
147
+ return pending;
152
148
  }
153
-
154
149
  /**
155
150
  * Is WebGPU usable here?
156
151
  *
@@ -160,18 +155,20 @@ function acquireDevice() {
160
155
  * @returns {Promise<boolean>}
161
156
  */
162
157
  export async function isWebGPUAvailable() {
163
- try {
164
- if (typeof navigator === 'undefined') return false;
165
- if (!navigator.gpu || typeof navigator.gpu.requestAdapter !== 'function') return false;
166
- // An adapter is the real test: `navigator.gpu` exists on machines whose
167
- // GPU is blocklisted, where every request still comes back null.
168
- const adapter = await navigator.gpu.requestAdapter();
169
- return Boolean(adapter);
170
- } catch {
171
- return false;
172
- }
158
+ try {
159
+ if (typeof navigator === 'undefined')
160
+ return false;
161
+ if (!navigator.gpu || typeof navigator.gpu.requestAdapter !== 'function')
162
+ return false;
163
+ // An adapter is the real test: `navigator.gpu` exists on machines whose
164
+ // GPU is blocklisted, where every request still comes back null.
165
+ const adapter = await navigator.gpu.requestAdapter();
166
+ return Boolean(adapter);
167
+ }
168
+ catch {
169
+ return false;
170
+ }
173
171
  }
174
-
175
172
  /**
176
173
  * Did the shader compile?
177
174
  *
@@ -183,20 +180,23 @@ export async function isWebGPUAvailable() {
183
180
  * @returns {Promise<boolean>}
184
181
  */
185
182
  async function compiles(module) {
186
- try {
187
- const query = module.getCompilationInfo ?? module.compilationInfo;
188
- if (typeof query !== 'function') return true;
189
- const info = await query.call(module);
190
- if (!info || !info.messages) return true;
191
- for (let i = 0; i < info.messages.length; i++) {
192
- if (info.messages[i].type === 'error') return false;
183
+ try {
184
+ const query = module.getCompilationInfo ?? module.compilationInfo;
185
+ if (typeof query !== 'function')
186
+ return true;
187
+ const info = await query.call(module);
188
+ if (!info || !info.messages)
189
+ return true;
190
+ for (let i = 0; i < info.messages.length; i++) {
191
+ if (info.messages[i].type === 'error')
192
+ return false;
193
+ }
194
+ return true;
195
+ }
196
+ catch {
197
+ return true;
193
198
  }
194
- return true;
195
- } catch {
196
- return true;
197
- }
198
199
  }
199
-
200
200
  /**
201
201
  * Draw a matrix into a canvas with WebGPU.
202
202
  *
@@ -209,161 +209,149 @@ async function compiles(module) {
209
209
  * availability before committing a canvas to this path.
210
210
  */
211
211
  export async function renderToCanvasWebGPU(matrix, canvas, options = {}) {
212
- let device = null;
213
- let texture = null;
214
- let uniforms = null;
215
-
216
- try {
217
- if (typeof navigator === 'undefined' || !navigator.gpu) return false;
218
-
219
- const opts = normalizeOptions(matrix, options);
220
- const { source, pixelWidth, pixelHeight } = opts;
221
-
222
- device = await acquireDevice();
223
- if (!device) return false;
224
-
225
- // Oversized symbols are a legitimate failure, not a crash: say so and let
226
- // the caller fall back to a path with no texture ceiling.
227
- // 8192 is the floor the specification guarantees, so it is the right
228
- // assumption when an implementation does not report its limits.
229
- const maxDimension = (device.limits && device.limits.maxTextureDimension2D) || 8192;
230
- if (source.width > maxDimension || source.height > maxDimension) return false;
231
-
232
- const context = canvas.getContext('webgpu');
233
- if (!context) return false;
234
-
235
- canvas.width = pixelWidth;
236
- canvas.height = pixelHeight;
237
-
238
- const format = navigator.gpu.getPreferredCanvasFormat();
239
- context.configure({ device, format, alphaMode: 'premultiplied' });
240
-
241
- // One byte per module. r8unorm is the narrowest format every WebGPU
242
- // implementation is required to support as a sampled texture.
243
- const pixels = new Uint8Array(source.width * source.height);
244
- for (let y = 0; y < source.height; y++) {
245
- for (let x = 0; x < source.width; x++) {
246
- pixels[y * source.width + x] = source.get(x, y) ? 255 : 0;
247
- }
248
- }
249
-
250
- texture = device.createTexture({
251
- size: { width: source.width, height: source.height, depthOrArrayLayers: 1 },
252
- format: 'r8unorm',
253
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
254
- });
255
-
256
- // `bytesPerRow` needs no 256-byte alignment here — that rule belongs to
257
- // buffer-to-texture copies, not to writeTexture's linear source data.
258
- device.queue.writeTexture(
259
- { texture },
260
- pixels,
261
- { offset: 0, bytesPerRow: source.width, rowsPerImage: source.height },
262
- { width: source.width, height: source.height, depthOrArrayLayers: 1 }
263
- );
264
-
265
- const sampler = device.createSampler({
266
- magFilter: 'nearest',
267
- minFilter: 'nearest',
268
- addressModeU: 'clamp-to-edge',
269
- addressModeV: 'clamp-to-edge',
270
- });
271
-
272
- // The canvas is configured as premultiplied, so the colours have to be
273
- // too — otherwise a translucent `light` would come out too bright and a
274
- // fully transparent one would tint the page behind it.
275
- const dark = parseColor(opts.dark);
276
- const light = parseColor(opts.light);
277
- const premultiplied = (c) => {
278
- const a = c[3] / 255;
279
- return [(c[0] / 255) * a, (c[1] / 255) * a, (c[2] / 255) * a, a];
280
- };
281
- const darkF = premultiplied(dark);
282
- const lightF = premultiplied(light);
283
-
284
- // std140-style layout: two vec4 then a vec2, rounded up to the struct's
285
- // 16-byte alignment. 48 bytes, of which the last 8 are padding.
286
- const style = new Float32Array(12);
287
- style.set(darkF, 0);
288
- style.set(lightF, 4);
289
- style[8] = source.width;
290
- style[9] = source.height;
291
-
292
- uniforms = device.createBuffer({
293
- size: style.byteLength,
294
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
295
- });
296
- device.queue.writeBuffer(uniforms, 0, style);
297
-
298
- const shader = device.createShaderModule({ code: SHADER });
299
- if (!(await compiles(shader))) return false;
300
-
301
- // An error scope is the WGSL analogue of checking LINK_STATUS: a rejected
302
- // pipeline is reported here instead of surfacing later as a lost device.
303
- let pipeline = null;
304
- if (typeof device.pushErrorScope === 'function') {
305
- device.pushErrorScope('validation');
306
- pipeline = device.createRenderPipeline({
307
- layout: 'auto',
308
- vertex: { module: shader, entryPoint: 'vertexMain' },
309
- fragment: { module: shader, entryPoint: 'fragmentMain', targets: [{ format }] },
310
- primitive: { topology: 'triangle-list' },
311
- });
312
- const failure = await device.popErrorScope();
313
- if (failure) return false;
314
- } else {
315
- pipeline = device.createRenderPipeline({
316
- layout: 'auto',
317
- vertex: { module: shader, entryPoint: 'vertexMain' },
318
- fragment: { module: shader, entryPoint: 'fragmentMain', targets: [{ format }] },
319
- primitive: { topology: 'triangle-list' },
320
- });
212
+ let device = null;
213
+ let texture = null;
214
+ let uniforms = null;
215
+ try {
216
+ if (typeof navigator === 'undefined' || !navigator.gpu)
217
+ return false;
218
+ const opts = normalizeOptions(matrix, options);
219
+ const { source, pixelWidth, pixelHeight } = opts;
220
+ device = await acquireDevice();
221
+ if (!device)
222
+ return false;
223
+ // Oversized symbols are a legitimate failure, not a crash: say so and let
224
+ // the caller fall back to a path with no texture ceiling.
225
+ // 8192 is the floor the specification guarantees, so it is the right
226
+ // assumption when an implementation does not report its limits.
227
+ const maxDimension = (device.limits && device.limits.maxTextureDimension2D) || 8192;
228
+ if (source.width > maxDimension || source.height > maxDimension)
229
+ return false;
230
+ const context = canvas.getContext('webgpu');
231
+ if (!context)
232
+ return false;
233
+ canvas.width = pixelWidth;
234
+ canvas.height = pixelHeight;
235
+ const format = navigator.gpu.getPreferredCanvasFormat();
236
+ context.configure({ device, format, alphaMode: 'premultiplied' });
237
+ // One byte per module. r8unorm is the narrowest format every WebGPU
238
+ // implementation is required to support as a sampled texture.
239
+ const pixels = new Uint8Array(source.width * source.height);
240
+ for (let y = 0; y < source.height; y++) {
241
+ for (let x = 0; x < source.width; x++) {
242
+ pixels[y * source.width + x] = source.get(x, y) ? 255 : 0;
243
+ }
244
+ }
245
+ texture = device.createTexture({
246
+ size: { width: source.width, height: source.height, depthOrArrayLayers: 1 },
247
+ format: 'r8unorm',
248
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
249
+ });
250
+ // `bytesPerRow` needs no 256-byte alignment here — that rule belongs to
251
+ // buffer-to-texture copies, not to writeTexture's linear source data.
252
+ device.queue.writeTexture({ texture }, pixels, { offset: 0, bytesPerRow: source.width, rowsPerImage: source.height }, { width: source.width, height: source.height, depthOrArrayLayers: 1 });
253
+ const sampler = device.createSampler({
254
+ magFilter: 'nearest',
255
+ minFilter: 'nearest',
256
+ addressModeU: 'clamp-to-edge',
257
+ addressModeV: 'clamp-to-edge',
258
+ });
259
+ // The canvas is configured as premultiplied, so the colours have to be
260
+ // too — otherwise a translucent `light` would come out too bright and a
261
+ // fully transparent one would tint the page behind it.
262
+ const dark = parseColor(opts.dark);
263
+ const light = parseColor(opts.light);
264
+ const premultiplied = (c) => {
265
+ const a = c[3] / 255;
266
+ return [(c[0] / 255) * a, (c[1] / 255) * a, (c[2] / 255) * a, a];
267
+ };
268
+ const darkF = premultiplied(dark);
269
+ const lightF = premultiplied(light);
270
+ // std140-style layout: two vec4 then a vec2, rounded up to the struct's
271
+ // 16-byte alignment. 48 bytes, of which the last 8 are padding.
272
+ const style = new Float32Array(12);
273
+ style.set(darkF, 0);
274
+ style.set(lightF, 4);
275
+ style[8] = source.width;
276
+ style[9] = source.height;
277
+ uniforms = device.createBuffer({
278
+ size: style.byteLength,
279
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
280
+ });
281
+ device.queue.writeBuffer(uniforms, 0, style);
282
+ const shader = device.createShaderModule({ code: SHADER });
283
+ if (!(await compiles(shader)))
284
+ return false;
285
+ // An error scope is the WGSL analogue of checking LINK_STATUS: a rejected
286
+ // pipeline is reported here instead of surfacing later as a lost device.
287
+ let pipeline = null;
288
+ if (typeof device.pushErrorScope === 'function') {
289
+ device.pushErrorScope('validation');
290
+ pipeline = device.createRenderPipeline({
291
+ layout: 'auto',
292
+ vertex: { module: shader, entryPoint: 'vertexMain' },
293
+ fragment: { module: shader, entryPoint: 'fragmentMain', targets: [{ format }] },
294
+ primitive: { topology: 'triangle-list' },
295
+ });
296
+ const failure = await device.popErrorScope();
297
+ if (failure)
298
+ return false;
299
+ }
300
+ else {
301
+ pipeline = device.createRenderPipeline({
302
+ layout: 'auto',
303
+ vertex: { module: shader, entryPoint: 'vertexMain' },
304
+ fragment: { module: shader, entryPoint: 'fragmentMain', targets: [{ format }] },
305
+ primitive: { topology: 'triangle-list' },
306
+ });
307
+ }
308
+ if (!pipeline)
309
+ return false;
310
+ const bindGroup = device.createBindGroup({
311
+ layout: pipeline.getBindGroupLayout(0),
312
+ entries: [
313
+ { binding: 0, resource: texture.createView() },
314
+ { binding: 1, resource: sampler },
315
+ { binding: 2, resource: { buffer: uniforms } },
316
+ ],
317
+ });
318
+ const encoder = device.createCommandEncoder();
319
+ const pass = encoder.beginRenderPass({
320
+ colorAttachments: [{
321
+ view: context.getCurrentTexture().createView(),
322
+ clearValue: { r: 0, g: 0, b: 0, a: 0 },
323
+ loadOp: 'clear',
324
+ storeOp: 'store',
325
+ }],
326
+ });
327
+ pass.setPipeline(pipeline);
328
+ pass.setBindGroup(0, bindGroup);
329
+ pass.draw(3);
330
+ pass.end();
331
+ device.queue.submit([encoder.finish()]);
332
+ // Wait for the draw before the `finally` below frees its inputs, so
333
+ // returning true genuinely means the pixels are there.
334
+ if (device.queue && typeof device.queue.onSubmittedWorkDone === 'function') {
335
+ await device.queue.onSubmittedWorkDone();
336
+ }
337
+ return true;
321
338
  }
322
- if (!pipeline) return false;
323
-
324
- const bindGroup = device.createBindGroup({
325
- layout: pipeline.getBindGroupLayout(0),
326
- entries: [
327
- { binding: 0, resource: texture.createView() },
328
- { binding: 1, resource: sampler },
329
- { binding: 2, resource: { buffer: uniforms } },
330
- ],
331
- });
332
-
333
- const encoder = device.createCommandEncoder();
334
- const pass = encoder.beginRenderPass({
335
- colorAttachments: [{
336
- view: context.getCurrentTexture().createView(),
337
- clearValue: { r: 0, g: 0, b: 0, a: 0 },
338
- loadOp: 'clear',
339
- storeOp: 'store',
340
- }],
341
- });
342
- pass.setPipeline(pipeline);
343
- pass.setBindGroup(0, bindGroup);
344
- pass.draw(3);
345
- pass.end();
346
- device.queue.submit([encoder.finish()]);
347
-
348
- // Wait for the draw before the `finally` below frees its inputs, so
349
- // returning true genuinely means the pixels are there.
350
- if (device.queue && typeof device.queue.onSubmittedWorkDone === 'function') {
351
- await device.queue.onSubmittedWorkDone();
339
+ catch {
340
+ return false;
352
341
  }
353
-
354
- return true;
355
- } catch {
356
- return false;
357
- } finally {
358
- // Release eagerly: a page generating many barcodes would otherwise hold
359
- // every texture until GC caught up, and GPU memory is not GC's priority.
360
- // The device itself is deliberately kept — it is shared, and destroying it
361
- // would blank every canvas already configured with it.
362
- try {
363
- if (texture && typeof texture.destroy === 'function') texture.destroy();
364
- if (uniforms && typeof uniforms.destroy === 'function') uniforms.destroy();
365
- } catch {
366
- /* device already gone */
342
+ finally {
343
+ // Release eagerly: a page generating many barcodes would otherwise hold
344
+ // every texture until GC caught up, and GPU memory is not GC's priority.
345
+ // The device itself is deliberately kept — it is shared, and destroying it
346
+ // would blank every canvas already configured with it.
347
+ try {
348
+ if (texture && typeof texture.destroy === 'function')
349
+ texture.destroy();
350
+ if (uniforms && typeof uniforms.destroy === 'function')
351
+ uniforms.destroy();
352
+ }
353
+ catch {
354
+ /* device already gone */
355
+ }
367
356
  }
368
- }
369
357
  }