/* * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt */ import {isString} from 'lodash'; import {loadImage, loadCancelableImage, requestIdleCallback} from '../../util/WebUtil.js'; /** * @global * @public * @typedef {Object} ImageContainer * Always contains key image and then anything else to specify the state * * @prop {Object} image * @prop {Object} src * @prop {String} dataUrl * @prop {Object} tileAttributes * @prop {Object} canCompress * */ /** * * @return {Promise} promise with new imageData */ /** * * @param {ImageContainer|Object|String} imageData the current image data or a html image object or the source of the * of an image to load * @param {Object} nextTileAttributes next state to process image * @param shouldProcess * @param processor * @return {Promise} */ export function retrieveAndProcessImage(imageData, nextTileAttributes, shouldProcess, processor) { if (!imageData) { return Promise.resolve(imageData); } else if (isString(imageData)) { let {promise, cancelImageLoad}= loadCancelableImage(imageData); promise= promise.then( (image) => modifyImage({image, tileAttributes:nextTileAttributes},nextTileAttributes,true, shouldProcess, processor)); return convertToReturn(promise, cancelImageLoad); } else if (imageData instanceof HTMLImageElement) { const v= modifyImage({image:imageData, tileAttributes:nextTileAttributes}, nextTileAttributes, true, shouldProcess, processor); return convertToReturn(v); } else { if (imageData.image) { // console.log('Image From Cache'); const v= modifyImage(imageData, nextTileAttributes,false, shouldProcess, processor); return convertToReturn(v); } else if (imageData.dataUrl) { let {promise, cancelImageLoad}= loadCancelableImage(imageData.dataUrl); promise= promise.then( (image) => modifyImage({image, tileAttributes:imageData.tileAttributes}, nextTileAttributes,false, shouldProcess, processor)); convertToReturn(promise, cancelImageLoad); } } return convertToReturn( Promise.reject(new Error('could note identify imageData: not string, HTMLImageElement, imageData.image, or imageData.dataUrl'))); } function convertToReturn(obj, cancelImageLoad= undefined) { if (obj.then) return {promise:obj,cancelImageLoad}; else if (obj.promise) return obj; else throw new Error('unexpected return object in ImageProcessor.retrieveAndProcessImage'); } /** * * @param {ImageData} imageData * @param {Object} nextTileAttributes * @param {boolean} newData * @param shouldProcess * @param processor * @return {ImageData} */ function modifyImage(imageData, nextTileAttributes, newData, shouldProcess, processor) { if (processor && shouldProcess && shouldProcess(imageData.image, newData, imageData.tileAttributes, nextTileAttributes) ) { // console.log('modifyImage'); return new Promise( (resolve, reject) => { requestIdleCallback( () => { const results= processImage(imageData.image, nextTileAttributes, processor); resolve( { image: results.canvas, compressible: results.compressible, tileAttributes: nextTileAttributes, } ); }, {timeout:100}); }); } else { return Promise.resolve(imageData); } } /** * * @param imageOrCanvas * @param tileAttributes * @param processor * @return {ImageData} */ function processImage(imageOrCanvas, tileAttributes, processor) { let canvas; let ctx; if (imageOrCanvas instanceof HTMLImageElement) { canvas = document.createElement('canvas'); const image= imageOrCanvas; ctx = canvas.getContext('2d'); canvas.width = image.width; canvas.height = image.height; ctx.drawImage(image, 0,0); } else { canvas= imageOrCanvas; ctx = canvas.getContext('2d'); } const imageData= ctx.getImageData(0,0,canvas.width,canvas.height); const newImageData= processor(imageData); ctx.putImageData(newImageData.imageData, 0, 0); return {canvas, compressible:newImageData.compressible}; }