1
1
<script lang="ts" setup>
2
2
import { toUint8Array } from ' js-base64'
3
- import { binaryToBlock , createDecoder , readFileHeaderMetaFromBuffer } from ' luby-transform'
4
-
3
+ import { binaryToBlock , readFileHeaderMetaFromBuffer } from ' luby-transform'
5
4
import QrScanner from ' qr-scanner'
5
+
6
+ import { createDecodeWorker } from ' ~/composables/decode-worker'
6
7
import { useKiloBytesNumberFormat } from ' ~/composables/intlNumberFormat'
7
8
import { useBytesRate } from ' ~/composables/timeseries'
8
9
import { CameraSignalStatus } from ' ~/types'
@@ -156,7 +157,15 @@ async function updateCameraStatus() {
156
157
}
157
158
}
158
159
159
- const decoder = ref (createDecoder ())
160
+ const decoderWorker = createDecodeWorker ()
161
+ onUnmounted (() => decoderWorker .dispose ())
162
+ const decoderStatus = ref <Awaited <ReturnType <typeof decoderWorker .getStatus >>>({
163
+ encodedBlocks: new Set (),
164
+ decodedData: [],
165
+ encodedCount: 0 ,
166
+ decodedCount: 0 ,
167
+ meta: null ! ,
168
+ })
160
169
161
170
const k = ref (0 )
162
171
const bytes = ref (0 )
@@ -170,7 +179,7 @@ const dataUrl = ref<string>()
170
179
const dots = useTemplateRef <HTMLDivElement []>(' dots' )
171
180
const status = ref <number []>([])
172
181
const decodedBlocks = computed (() => status .value .filter (i => i === 1 ).length )
173
- const receivedBytes = computed (() => decoder .value .encodedCount * (decoder .value .meta ?.data .length ?? 0 ))
182
+ const receivedBytes = computed (() => decoderStatus .value .encodedCount * (decoderStatus .value .meta ?.data .length ?? 0 ))
174
183
175
184
const filename = ref <string | undefined >()
176
185
const contentType = ref <string | undefined >()
@@ -182,10 +191,10 @@ const receivedBytesFormatted = useKiloBytesNumberFormat(computed(() => (received
182
191
function getStatus() {
183
192
const array = Array .from ({ length: k .value }, () => 0 )
184
193
for (let i = 0 ; i < k .value ; i ++ ) {
185
- if (decoder .value .decodedData [i ] != null )
194
+ if (decoderStatus .value .decodedData [i ] != null )
186
195
array [i ] = 1
187
196
}
188
- for (const block of decoder .value .encodedBlocks ) {
197
+ for (const block of decoderStatus .value .encodedBlocks ) {
189
198
for (const i of block .indices ) {
190
199
if (array [i ] === 0 || array [i ]! > block .indices .length ) {
191
200
array [i ] = block .indices .length
@@ -231,14 +240,15 @@ function toDataURL(data: Uint8Array | string | any, type: string): string {
231
240
}
232
241
}
233
242
243
+ let decoderInitPromise: Promise <any > | undefined
234
244
async function scanFrame(result : QrScanner .ScanResult ) {
235
245
cameraSignalStatus .value = CameraSignalStatus .Ready
236
246
237
247
if (! result .data )
238
248
return
239
249
240
250
bytesReceived .value += result .data .length
241
- totalValidBytesReceived .value = decoder .value .encodedCount * (decoder .value .meta ?.data .length ?? 0 )
251
+ totalValidBytesReceived .value = decoderStatus .value .encodedCount * (decoderStatus .value .meta ?.data .length ?? 0 )
242
252
243
253
// Do not process the same QR code twice
244
254
if (cached .has (result .data ))
@@ -252,7 +262,7 @@ async function scanFrame(result: QrScanner.ScanResult) {
252
262
const data = binaryToBlock (binary )
253
263
// Data set changed, reset decoder
254
264
if (checksum .value !== data .checksum ) {
255
- decoder . value = createDecoder ()
265
+ decoderInitPromise = decoderWorker . createDecoder ()
256
266
checksum .value = data .checksum
257
267
bytes .value = data .bytes
258
268
k .value = data .k
@@ -268,17 +278,19 @@ async function scanFrame(result: QrScanner.ScanResult) {
268
278
else if (endTime .value ) {
269
279
return
270
280
}
281
+ await decoderInitPromise
271
282
272
283
cached .add (result .data )
273
284
k .value = data .k
274
285
275
286
data .indices .map (i => pluse (i ))
276
- const success = decoder .value .addBlock (data )
287
+ const success = await decoderWorker .addBlock (data )
288
+ decoderStatus .value = await decoderWorker .getStatus ()
277
289
status .value = getStatus ()
278
290
if (success ) {
279
291
endTime .value = performance .now ()
280
292
281
- const merged = decoder . value . getDecoded ()!
293
+ const merged = ( await decoderWorker . getDecoded () )!
282
294
const [mergedData, meta] = readFileHeaderMetaFromBuffer (merged )
283
295
dataUrl .value = toDataURL (mergedData , meta .contentType )
284
296
@@ -350,7 +362,7 @@ function now() {
350
362
<span text-neutral-500 >Decoded</span >
351
363
<span text-right md:text-left >{{ decodedBlocks }}</span >
352
364
<span text-neutral-500 >Received blocks</span >
353
- <span text-right md:text-left >{{ decoder .encodedCount }}</span >
365
+ <span text-right md:text-left >{{ decoderStatus .encodedCount }}</span >
354
366
<span text-neutral-500 >Expected bytes</span >
355
367
<span text-right md:text-left >{{ bytesFormatted }}</span >
356
368
<span text-neutral-500 >Received bytes</span >
@@ -427,7 +439,7 @@ function now() {
427
439
428
440
<Collapsable label =" Blocks" >
429
441
<div flex =" ~ gap-1 wrap" max-w-150 text-xs >
430
- <div v-for =" i, idx of decoder .encodedBlocks" :key =" idx" border =" ~ gray/10 rounded" p1 >
442
+ <div v-for =" i, idx of decoderStatus .encodedBlocks" :key =" idx" border =" ~ gray/10 rounded" p1 >
431
443
<template v-for =" x , idy of i .indices " :key =" x " >
432
444
<span v-if =" idy !== 0" op25 >, </span >
433
445
<span :style =" { color: `hsl(${x * 40}, 40%, 60%)` }" >{{ x }}</span >
0 commit comments