client_worker.js (2753B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 let decoder = null; 7 8 // Serialize work; plus postpone processing until decoder is ready. 9 let jobs = []; 10 11 const processJobs = () => { 12 // Decoder not yet loaded. 13 if (!decoder) { 14 return; 15 } 16 17 while (true) { 18 let job = null; 19 // Currently we do not do progressive; process only "inputComplete" jobs. 20 for (let i = 0; i < jobs.length; ++i) { 21 if (!jobs[i].inputComplete) { 22 continue; 23 } 24 job = jobs[i]; 25 jobs[i] = jobs[jobs.length - 1]; 26 jobs.pop(); 27 break; 28 } 29 if (!job) { 30 return; 31 } 32 console.log('CW job: ' + job.uid); 33 const input = job.input; 34 let totalInputLength = 0; 35 for (let i = 0; i < input.length; i++) { 36 totalInputLength += input[i].length; 37 } 38 39 // TODO(eustas): persist to reduce fragmentation? 40 const buffer = decoder._malloc(totalInputLength); 41 // TODO(eustas): check OOM 42 let offset = 0; 43 for (let i = 0; i < input.length; ++i) { 44 decoder.HEAP8.set(input[i], buffer + offset); 45 offset += input[i].length; 46 } 47 let t0 = Date.now(); 48 // TODO(eustas): check result 49 const result = decoder._jxlDecompress(buffer, totalInputLength); 50 let t1 = Date.now(); 51 const msg = 'Decoded ' + job.url + ' in ' + (t1 - t0) + 'ms'; 52 // console.log(msg); 53 decoder._free(buffer); 54 const outputLength = decoder.HEAP32[result >> 2]; 55 const outputAddr = decoder.HEAP32[(result + 4) >> 2]; 56 const output = new Uint8Array(outputLength); 57 const outputSrc = new Uint8Array(decoder.HEAP8.buffer); 58 output.set(outputSrc.slice(outputAddr, outputAddr + outputLength)); 59 decoder._jxlCleanup(result); 60 const response = {uid: job.uid, data: output, msg: msg}; 61 postMessage(response, [output.buffer]); 62 } 63 }; 64 65 onmessage = function(event) { 66 const data = event.data; 67 console.log('CW received: ' + data.op); 68 if (data.op === 'decodeJxl') { 69 let job = null; 70 for (let i = 0; i < jobs.length; ++i) { 71 if (jobs[i].uid === data.uid) { 72 job = jobs[i]; 73 break; 74 } 75 } 76 if (!job) { 77 job = {uid: data.uid, input: [], inputComplete: false, url: data.url}; 78 jobs.push(job); 79 } 80 if (data.data) { 81 job.input.push(data.data); 82 } else { 83 job.inputComplete = true; 84 } 85 processJobs(); 86 } 87 }; 88 89 const onLoadJxlModule = (instance) => { 90 decoder = instance; 91 processJobs(); 92 }; 93 94 importScripts('jxl_decoder.js'); 95 const config = { 96 mainScriptUrlOrBlob: 'https://jxl-demo.netlify.app/jxl_decoder.js', 97 INITIAL_MEMORY: 16 * 1024 * 1024, 98 }; 99 JxlDecoderModule(config).then(onLoadJxlModule);