UNPKG

@lightningtv/renderer

Version:
200 lines 8.62 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2023 Comcast Cable Communications Management, LLC. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {} from '../textures/Texture.js'; /** * Note that, within the createImageWorker function, we must only use ES5 code to keep it ES5-valid after babelifying, as * the converted code of this section is converted to a blob and used as the js of the web worker thread. * * The createImageWorker function is a web worker that fetches an image from a URL and returns an ImageBitmap object. * The eslint @typescript rule is disabled for the entire function because the function is converted to a blob and used as the * js of the web worker thread, so the typescript syntax is not valid in this context. */ /* eslint-disable */ function createImageWorker() { function hasAlphaChannel(mimeType) { return mimeType.indexOf('image/png') !== -1; } function getImage(src, premultiplyAlpha, x, y, width, height, options) { return new Promise(function (resolve, reject) { var supportsOptionsCreateImageBitmap = options.supportsOptionsCreateImageBitmap; var supportsFullCreateImageBitmap = options.supportsFullCreateImageBitmap; var xhr = new XMLHttpRequest(); xhr.open('GET', src, true); xhr.responseType = 'blob'; xhr.onload = function () { // On most devices like WebOS and Tizen, the file protocol returns 0 while http(s) protocol returns 200 if (xhr.status !== 200 && xhr.status !== 0) { return reject(new Error('Failed to load image: ' + xhr.statusText)); } var blob = xhr.response; var withAlphaChannel = premultiplyAlpha !== undefined ? premultiplyAlpha : hasAlphaChannel(blob.type); // createImageBitmap with crop and options if (supportsFullCreateImageBitmap === true && width !== null && height !== null) { createImageBitmap(blob, x || 0, y || 0, width, height, { premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none', colorSpaceConversion: 'none', imageOrientation: 'none', }) .then(function (data) { resolve({ data, premultiplyAlpha: premultiplyAlpha }); }) .catch(function (error) { reject(error); }); return; } else if (supportsOptionsCreateImageBitmap === false && supportsOptionsCreateImageBitmap === false) { // Fallback for browsers that do not support createImageBitmap with options // this is supported for Chrome v50 to v52/54 that doesn't support options createImageBitmap(blob) .then(function (data) { resolve({ data, premultiplyAlpha: premultiplyAlpha }); }) .catch(function (error) { reject(error); }); } else { createImageBitmap(blob, { premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none', colorSpaceConversion: 'none', imageOrientation: 'none', }) .then(function (data) { resolve({ data, premultiplyAlpha: premultiplyAlpha }); }) .catch(function (error) { reject(error); }); } }; xhr.onerror = function () { reject(new Error('Network error occurred while trying to fetch the image.')); }; xhr.send(); }); } self.onmessage = (event) => { var src = event.data.src; var id = event.data.id; var premultiplyAlpha = event.data.premultiplyAlpha; var x = event.data.sx; var y = event.data.sy; var width = event.data.sw; var height = event.data.sh; // these will be set to true if the browser supports the createImageBitmap options or full var supportsOptionsCreateImageBitmap = false; var supportsFullCreateImageBitmap = false; getImage(src, premultiplyAlpha, x, y, width, height, { supportsOptionsCreateImageBitmap, supportsFullCreateImageBitmap, }) .then(function (data) { self.postMessage({ id: id, src: src, data: data }); }) .catch(function (error) { self.postMessage({ id: id, src: src, error: error.message }); }); }; } /* eslint-enable */ export class ImageWorkerManager { imageWorkersEnabled = true; messageManager = {}; workers = []; workerIndex = 0; nextId = 0; constructor(numImageWorkers, createImageBitmapSupport) { this.workers = this.createWorkers(numImageWorkers, createImageBitmapSupport); this.workers.forEach((worker) => { worker.onmessage = this.handleMessage.bind(this); }); } handleMessage(event) { const { id, data, error } = event.data; const msg = this.messageManager[id]; if (msg) { const [resolve, reject] = msg; delete this.messageManager[id]; if (error) { reject(new Error(error)); } else { resolve(data); } } } createWorkers(numWorkers = 1, createImageBitmapSupport) { let workerCode = `(${createImageWorker.toString()})()`; // Replace placeholders with actual initialization values if (createImageBitmapSupport.options === true) { workerCode = workerCode.replace('var supportsOptionsCreateImageBitmap = false;', 'var supportsOptionsCreateImageBitmap = true;'); } if (createImageBitmapSupport.full === true) { workerCode = workerCode.replace('var supportsOptionsCreateImageBitmap = false;', 'var supportsOptionsCreateImageBitmap = true;'); workerCode = workerCode.replace('var supportsFullCreateImageBitmap = false;', 'var supportsFullCreateImageBitmap = true;'); } workerCode = workerCode.replace('"use strict";', ''); const blob = new Blob([workerCode], { type: 'application/javascript', }); const blobURL = (self.URL ? URL : webkitURL).createObjectURL(blob); const workers = []; for (let i = 0; i < numWorkers; i++) { workers.push(new Worker(blobURL)); } return workers; } getNextWorker() { const worker = this.workers[this.workerIndex]; this.workerIndex = (this.workerIndex + 1) % this.workers.length; return worker; } getImage(src, premultiplyAlpha, sx, sy, sw, sh) { return new Promise((resolve, reject) => { try { if (this.workers) { const id = this.nextId++; this.messageManager[id] = [resolve, reject]; const nextWorker = this.getNextWorker(); if (nextWorker) { nextWorker.postMessage({ id, src: src, premultiplyAlpha, sx, sy, sw, sh, }); } } } catch (error) { reject(error); } }); } } //# sourceMappingURL=ImageWorker.js.map