// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. let decoder = null; // Serialize work; plus postpone processing until decoder is ready. let jobs = []; const processJobs = () => { // Decoder not yet loaded. if (!decoder) { return; } while (true) { let job = null; // Currently we do not do progressive; process only "inputComplete" jobs. for (let i = 0; i < jobs.length; ++i) { if (!jobs[i].inputComplete) { continue; } job = jobs[i]; jobs[i] = jobs[jobs.length - 1]; jobs.pop(); break; } if (!job) { return; } console.log('CW job: ' + job.uid); const input = job.input; let totalInputLength = 0; for (let i = 0; i < input.length; i++) { totalInputLength += input[i].length; } // TODO(eustas): persist to reduce fragmentation? const buffer = decoder._malloc(totalInputLength); // TODO(eustas): check OOM let offset = 0; for (let i = 0; i < input.length; ++i) { decoder.HEAP8.set(input[i], buffer + offset); offset += input[i].length; } let t0 = Date.now(); // TODO(eustas): check result const result = decoder._jxlDecompress(buffer, totalInputLength); let t1 = Date.now(); const msg = 'Decoded ' + job.url + ' in ' + (t1 - t0) + 'ms'; // console.log(msg); decoder._free(buffer); const outputLength = decoder.HEAP32[result >> 2]; const outputAddr = decoder.HEAP32[(result + 4) >> 2]; const output = new Uint8Array(outputLength); const outputSrc = new Uint8Array(decoder.HEAP8.buffer); output.set(outputSrc.slice(outputAddr, outputAddr + outputLength)); decoder._jxlCleanup(result); const response = {uid: job.uid, data: output, msg: msg}; postMessage(response, [output.buffer]); } }; onmessage = function(event) { const data = event.data; console.log('CW received: ' + data.op); if (data.op === 'decodeJxl') { let job = null; for (let i = 0; i < jobs.length; ++i) { if (jobs[i].uid === data.uid) { job = jobs[i]; break; } } if (!job) { job = {uid: data.uid, input: [], inputComplete: false, url: data.url}; jobs.push(job); } if (data.data) { job.input.push(data.data); } else { job.inputComplete = true; } processJobs(); } }; const onLoadJxlModule = (instance) => { decoder = instance; processJobs(); }; importScripts('jxl_decoder.js'); const config = { mainScriptUrlOrBlob: 'https://jxl-demo.netlify.app/jxl_decoder.js', INITIAL_MEMORY: 16 * 1024 * 1024, }; JxlDecoderModule(config).then(onLoadJxlModule);