From: Tim Düsterhus Date: Sat, 16 May 2020 11:23:48 +0000 (+0200) Subject: Update pica to 5.1.0 X-Git-Tag: 5.3.0_Alpha_1~211^2~2 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=082fd2fe5591a22e9160597c78e55ef24f940411;p=GitHub%2FWoltLab%2FWCF.git Update pica to 5.1.0 --- diff --git a/wcfsetup/install/files/js/3rdParty/pica.js b/wcfsetup/install/files/js/3rdParty/pica.js index 08c620e46e..d1c5e545c5 100644 --- a/wcfsetup/install/files/js/3rdParty/pica.js +++ b/wcfsetup/install/files/js/3rdParty/pica.js @@ -1,79 +1,58 @@ -/* (The MIT License) - -Copyright (C) 2014-2017 by Vitaly Puzrin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. */ -/* pica 5.0.0 nodeca/pica */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pica = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0, - wasm: __requested_features.indexOf('wasm') >= 0 - }; - Multimath.call(this, features); - this.features = { - js: features.js, - wasm: features.wasm && this.has_wasm - }; - this.use(mm_unsharp_mask); - this.use(mm_resize); - } - - inherits(MathLib, Multimath); - - MathLib.prototype.resizeAndUnsharp = function resizeAndUnsharp(options, cache) { - var result = this.resize(options, cache); - - if (options.unsharpAmount) { - this.unsharp_mask(result, options.toWidth, options.toHeight, options.unsharpAmount, options.unsharpRadius, options.unsharpThreshold); - } - - return result; - }; - - module.exports = MathLib; - - },{"./mm_resize":4,"inherits":15,"multimath":16,"multimath/lib/unsharp_mask":19}],2:[function(require,module,exports){ +'use strict'; + +var inherits = require('inherits'); + +var Multimath = require('multimath'); + +var mm_unsharp_mask = require('multimath/lib/unsharp_mask'); + +var mm_resize = require('./mm_resize'); + +function MathLib(requested_features) { + var __requested_features = requested_features || []; + + var features = { + js: __requested_features.indexOf('js') >= 0, + wasm: __requested_features.indexOf('wasm') >= 0 + }; + Multimath.call(this, features); + this.features = { + js: features.js, + wasm: features.wasm && this.has_wasm() + }; + this.use(mm_unsharp_mask); + this.use(mm_resize); +} + +inherits(MathLib, Multimath); + +MathLib.prototype.resizeAndUnsharp = function resizeAndUnsharp(options, cache) { + var result = this.resize(options, cache); + + if (options.unsharpAmount) { + this.unsharp_mask(result, options.toWidth, options.toHeight, options.unsharpAmount, options.unsharpRadius, options.unsharpThreshold); + } + + return result; +}; + +module.exports = MathLib; + +},{"./mm_resize":4,"inherits":15,"multimath":16,"multimath/lib/unsharp_mask":19}],2:[function(require,module,exports){ // Resize convolvers, pure JS implementation // - 'use strict'; // Precision of fixed FP values +'use strict'; // Precision of fixed FP values //var FIXED_FRAC_BITS = 14; - - function clampTo8(i) { - return i < 0 ? 0 : i > 255 ? 255 : i; - } // Convolve image in horizontal directions and transpose output. In theory, + +function clampTo8(i) { + return i < 0 ? 0 : i > 255 ? 255 : i; +} // Convolve image in horizontal directions and transpose output. In theory, // transpose allow: // // - use the same convolver for both passes (this fails due different @@ -82,192 +61,192 @@ THE SOFTWARE. */ // // But in real life this doesn't work :) // - - - function convolveHorizontally(src, dest, srcW, srcH, destW, filters) { - var r, g, b, a; - var filterPtr, filterShift, filterSize; - var srcPtr, srcY, destX, filterVal; - var srcOffset = 0, - destOffset = 0; // For each row - - for (srcY = 0; srcY < srcH; srcY++) { - filterPtr = 0; // Apply precomputed filters to each destination row point - - for (destX = 0; destX < destW; destX++) { - // Get the filter that determines the current output pixel. - filterShift = filters[filterPtr++]; - filterSize = filters[filterPtr++]; - srcPtr = srcOffset + filterShift * 4 | 0; - r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a - - for (; filterSize > 0; filterSize--) { - filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10) - // Big thanks to @mraleph (Vyacheslav Egorov) for the tip. - - a = a + filterVal * src[srcPtr + 3] | 0; - b = b + filterVal * src[srcPtr + 2] | 0; - g = g + filterVal * src[srcPtr + 1] | 0; - r = r + filterVal * src[srcPtr] | 0; - srcPtr = srcPtr + 4 | 0; - } // Bring this value back in range. All of the filter scaling factors - // are in fixed point with FIXED_FRAC_BITS bits of fractional part. - // - // (!) Add 1/2 of value before clamping to get proper rounding. In other - // case brightness loss will be noticeable if you resize image with white - // border and place it on white background. - // - - - dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset] = clampTo8(r + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - destOffset = destOffset + srcH * 4 | 0; - } - - destOffset = (srcY + 1) * 4 | 0; - srcOffset = (srcY + 1) * srcW * 4 | 0; - } - } // Technically, convolvers are the same. But input array and temporary + + +function convolveHorizontally(src, dest, srcW, srcH, destW, filters) { + var r, g, b, a; + var filterPtr, filterShift, filterSize; + var srcPtr, srcY, destX, filterVal; + var srcOffset = 0, + destOffset = 0; // For each row + + for (srcY = 0; srcY < srcH; srcY++) { + filterPtr = 0; // Apply precomputed filters to each destination row point + + for (destX = 0; destX < destW; destX++) { + // Get the filter that determines the current output pixel. + filterShift = filters[filterPtr++]; + filterSize = filters[filterPtr++]; + srcPtr = srcOffset + filterShift * 4 | 0; + r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a + + for (; filterSize > 0; filterSize--) { + filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10) + // Big thanks to @mraleph (Vyacheslav Egorov) for the tip. + + a = a + filterVal * src[srcPtr + 3] | 0; + b = b + filterVal * src[srcPtr + 2] | 0; + g = g + filterVal * src[srcPtr + 1] | 0; + r = r + filterVal * src[srcPtr] | 0; + srcPtr = srcPtr + 4 | 0; + } // Bring this value back in range. All of the filter scaling factors + // are in fixed point with FIXED_FRAC_BITS bits of fractional part. + // + // (!) Add 1/2 of value before clamping to get proper rounding. In other + // case brightness loss will be noticeable if you resize image with white + // border and place it on white background. + // + + + dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset] = clampTo8(r + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + destOffset = destOffset + srcH * 4 | 0; + } + + destOffset = (srcY + 1) * 4 | 0; + srcOffset = (srcY + 1) * srcW * 4 | 0; + } +} // Technically, convolvers are the same. But input array and temporary // buffer can be of different type (especially, in old browsers). So, // keep code in separate functions to avoid deoptimizations & speed loss. - - - function convolveVertically(src, dest, srcW, srcH, destW, filters) { - var r, g, b, a; - var filterPtr, filterShift, filterSize; - var srcPtr, srcY, destX, filterVal; - var srcOffset = 0, - destOffset = 0; // For each row - - for (srcY = 0; srcY < srcH; srcY++) { - filterPtr = 0; // Apply precomputed filters to each destination row point - - for (destX = 0; destX < destW; destX++) { - // Get the filter that determines the current output pixel. - filterShift = filters[filterPtr++]; - filterSize = filters[filterPtr++]; - srcPtr = srcOffset + filterShift * 4 | 0; - r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a - - for (; filterSize > 0; filterSize--) { - filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10) - // Big thanks to @mraleph (Vyacheslav Egorov) for the tip. - - a = a + filterVal * src[srcPtr + 3] | 0; - b = b + filterVal * src[srcPtr + 2] | 0; - g = g + filterVal * src[srcPtr + 1] | 0; - r = r + filterVal * src[srcPtr] | 0; - srcPtr = srcPtr + 4 | 0; - } // Bring this value back in range. All of the filter scaling factors - // are in fixed point with FIXED_FRAC_BITS bits of fractional part. - // - // (!) Add 1/2 of value before clamping to get proper rounding. In other - // case brightness loss will be noticeable if you resize image with white - // border and place it on white background. - // - - - dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - dest[destOffset] = clampTo8(r + (1 << 13) >> 14 - /*FIXED_FRAC_BITS*/ - ); - destOffset = destOffset + srcH * 4 | 0; - } - - destOffset = (srcY + 1) * 4 | 0; - srcOffset = (srcY + 1) * srcW * 4 | 0; - } - } - - module.exports = { - convolveHorizontally: convolveHorizontally, - convolveVertically: convolveVertically - }; - - },{}],3:[function(require,module,exports){ + + +function convolveVertically(src, dest, srcW, srcH, destW, filters) { + var r, g, b, a; + var filterPtr, filterShift, filterSize; + var srcPtr, srcY, destX, filterVal; + var srcOffset = 0, + destOffset = 0; // For each row + + for (srcY = 0; srcY < srcH; srcY++) { + filterPtr = 0; // Apply precomputed filters to each destination row point + + for (destX = 0; destX < destW; destX++) { + // Get the filter that determines the current output pixel. + filterShift = filters[filterPtr++]; + filterSize = filters[filterPtr++]; + srcPtr = srcOffset + filterShift * 4 | 0; + r = g = b = a = 0; // Apply the filter to the row to get the destination pixel r, g, b, a + + for (; filterSize > 0; filterSize--) { + filterVal = filters[filterPtr++]; // Use reverse order to workaround deopts in old v8 (node v.10) + // Big thanks to @mraleph (Vyacheslav Egorov) for the tip. + + a = a + filterVal * src[srcPtr + 3] | 0; + b = b + filterVal * src[srcPtr + 2] | 0; + g = g + filterVal * src[srcPtr + 1] | 0; + r = r + filterVal * src[srcPtr] | 0; + srcPtr = srcPtr + 4 | 0; + } // Bring this value back in range. All of the filter scaling factors + // are in fixed point with FIXED_FRAC_BITS bits of fractional part. + // + // (!) Add 1/2 of value before clamping to get proper rounding. In other + // case brightness loss will be noticeable if you resize image with white + // border and place it on white background. + // + + + dest[destOffset + 3] = clampTo8(a + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset + 2] = clampTo8(b + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset + 1] = clampTo8(g + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + dest[destOffset] = clampTo8(r + (1 << 13) >> 14 + /*FIXED_FRAC_BITS*/ + ); + destOffset = destOffset + srcH * 4 | 0; + } + + destOffset = (srcY + 1) * 4 | 0; + srcOffset = (srcY + 1) * srcW * 4 | 0; + } +} + +module.exports = { + convolveHorizontally: convolveHorizontally, + convolveVertically: convolveVertically +}; + +},{}],3:[function(require,module,exports){ // This is autogenerated file from math.wasm, don't edit. // - 'use strict'; - /* eslint-disable max-len */ - - module.exports = 'AGFzbQEAAAABFAJgBn9/f39/fwBgB39/f39/f38AAg8BA2VudgZtZW1vcnkCAAEDAwIAAQQEAXAAAAcZAghjb252b2x2ZQAACmNvbnZvbHZlSFYAAQkBAArmAwLBAwEQfwJAIANFDQAgBEUNACAFQQRqIRVBACEMQQAhDQNAIA0hDkEAIRFBACEHA0AgB0ECaiESAn8gBSAHQQF0IgdqIgZBAmouAQAiEwRAQQAhCEEAIBNrIRQgFSAHaiEPIAAgDCAGLgEAakECdGohEEEAIQlBACEKQQAhCwNAIBAoAgAiB0EYdiAPLgEAIgZsIAtqIQsgB0H/AXEgBmwgCGohCCAHQRB2Qf8BcSAGbCAKaiEKIAdBCHZB/wFxIAZsIAlqIQkgD0ECaiEPIBBBBGohECAUQQFqIhQNAAsgEiATagwBC0EAIQtBACEKQQAhCUEAIQggEgshByABIA5BAnRqIApBgMAAakEOdSIGQf8BIAZB/wFIG0EQdEGAgPwHcUEAIAZBAEobIAtBgMAAakEOdSIGQf8BIAZB/wFIG0EYdEEAIAZBAEobciAJQYDAAGpBDnUiBkH/ASAGQf8BSBtBCHRBgP4DcUEAIAZBAEobciAIQYDAAGpBDnUiBkH/ASAGQf8BSBtB/wFxQQAgBkEAShtyNgIAIA4gA2ohDiARQQFqIhEgBEcNAAsgDCACaiEMIA1BAWoiDSADRw0ACwsLIQACQEEAIAIgAyAEIAUgABAAIAJBACAEIAUgBiABEAALCw=='; - - },{}],4:[function(require,module,exports){ - 'use strict'; - - module.exports = { - name: 'resize', - fn: require('./resize'), - wasm_fn: require('./resize_wasm'), - wasm_src: require('./convolve_wasm_base64') - }; - - },{"./convolve_wasm_base64":3,"./resize":5,"./resize_wasm":8}],5:[function(require,module,exports){ - 'use strict'; - - var createFilters = require('./resize_filter_gen'); - - var convolveHorizontally = require('./convolve').convolveHorizontally; - - var convolveVertically = require('./convolve').convolveVertically; - - function resetAlpha(dst, width, height) { - var ptr = 3, - len = width * height * 4 | 0; - - while (ptr < len) { - dst[ptr] = 0xFF; - ptr = ptr + 4 | 0; - } - } - - module.exports = function resize(options) { - var src = options.src; - var srcW = options.width; - var srcH = options.height; - var destW = options.toWidth; - var destH = options.toHeight; - var scaleX = options.scaleX || options.toWidth / options.width; - var scaleY = options.scaleY || options.toHeight / options.height; - var offsetX = options.offsetX || 0; - var offsetY = options.offsetY || 0; - var dest = options.dest || new Uint8Array(destW * destH * 4); - var quality = typeof options.quality === 'undefined' ? 3 : options.quality; - var alpha = options.alpha || false; - var filtersX = createFilters(quality, srcW, destW, scaleX, offsetX), - filtersY = createFilters(quality, srcH, destH, scaleY, offsetY); - var tmp = new Uint8Array(destW * srcH * 4); // To use single function we need src & tmp of the same type. - // But src can be CanvasPixelArray, and tmp - Uint8Array. So, keep - // vertical and horizontal passes separately to avoid deoptimization. - - convolveHorizontally(src, tmp, srcW, srcH, destW, filtersX); - convolveVertically(tmp, dest, srcH, destW, destH, filtersY); // That's faster than doing checks in convolver. - // !!! Note, canvas data is not premultipled. We don't need other - // alpha corrections. - - if (!alpha) resetAlpha(dest, destW, destH); - return dest; - }; - - },{"./convolve":2,"./resize_filter_gen":6}],6:[function(require,module,exports){ +'use strict'; +/* eslint-disable max-len */ + +module.exports = 'AGFzbQEAAAABFAJgBn9/f39/fwBgB39/f39/f38AAg8BA2VudgZtZW1vcnkCAAEDAwIAAQQEAXAAAAcZAghjb252b2x2ZQAACmNvbnZvbHZlSFYAAQkBAArmAwLBAwEQfwJAIANFDQAgBEUNACAFQQRqIRVBACEMQQAhDQNAIA0hDkEAIRFBACEHA0AgB0ECaiESAn8gBSAHQQF0IgdqIgZBAmouAQAiEwRAQQAhCEEAIBNrIRQgFSAHaiEPIAAgDCAGLgEAakECdGohEEEAIQlBACEKQQAhCwNAIBAoAgAiB0EYdiAPLgEAIgZsIAtqIQsgB0H/AXEgBmwgCGohCCAHQRB2Qf8BcSAGbCAKaiEKIAdBCHZB/wFxIAZsIAlqIQkgD0ECaiEPIBBBBGohECAUQQFqIhQNAAsgEiATagwBC0EAIQtBACEKQQAhCUEAIQggEgshByABIA5BAnRqIApBgMAAakEOdSIGQf8BIAZB/wFIG0EQdEGAgPwHcUEAIAZBAEobIAtBgMAAakEOdSIGQf8BIAZB/wFIG0EYdEEAIAZBAEobciAJQYDAAGpBDnUiBkH/ASAGQf8BSBtBCHRBgP4DcUEAIAZBAEobciAIQYDAAGpBDnUiBkH/ASAGQf8BSBtB/wFxQQAgBkEAShtyNgIAIA4gA2ohDiARQQFqIhEgBEcNAAsgDCACaiEMIA1BAWoiDSADRw0ACwsLIQACQEEAIAIgAyAEIAUgABAAIAJBACAEIAUgBiABEAALCw=='; + +},{}],4:[function(require,module,exports){ +'use strict'; + +module.exports = { + name: 'resize', + fn: require('./resize'), + wasm_fn: require('./resize_wasm'), + wasm_src: require('./convolve_wasm_base64') +}; + +},{"./convolve_wasm_base64":3,"./resize":5,"./resize_wasm":8}],5:[function(require,module,exports){ +'use strict'; + +var createFilters = require('./resize_filter_gen'); + +var convolveHorizontally = require('./convolve').convolveHorizontally; + +var convolveVertically = require('./convolve').convolveVertically; + +function resetAlpha(dst, width, height) { + var ptr = 3, + len = width * height * 4 | 0; + + while (ptr < len) { + dst[ptr] = 0xFF; + ptr = ptr + 4 | 0; + } +} + +module.exports = function resize(options) { + var src = options.src; + var srcW = options.width; + var srcH = options.height; + var destW = options.toWidth; + var destH = options.toHeight; + var scaleX = options.scaleX || options.toWidth / options.width; + var scaleY = options.scaleY || options.toHeight / options.height; + var offsetX = options.offsetX || 0; + var offsetY = options.offsetY || 0; + var dest = options.dest || new Uint8Array(destW * destH * 4); + var quality = typeof options.quality === 'undefined' ? 3 : options.quality; + var alpha = options.alpha || false; + var filtersX = createFilters(quality, srcW, destW, scaleX, offsetX), + filtersY = createFilters(quality, srcH, destH, scaleY, offsetY); + var tmp = new Uint8Array(destW * srcH * 4); // To use single function we need src & tmp of the same type. + // But src can be CanvasPixelArray, and tmp - Uint8Array. So, keep + // vertical and horizontal passes separately to avoid deoptimization. + + convolveHorizontally(src, tmp, srcW, srcH, destW, filtersX); + convolveVertically(tmp, dest, srcH, destW, destH, filtersY); // That's faster than doing checks in convolver. + // !!! Note, canvas data is not premultipled. We don't need other + // alpha corrections. + + if (!alpha) resetAlpha(dest, destW, destH); + return dest; +}; + +},{"./convolve":2,"./resize_filter_gen":6}],6:[function(require,module,exports){ // Calculate convolution filters for each destination point, // and pack data to Int16Array: // @@ -277,335 +256,335 @@ THE SOFTWARE. */ // - length - filter length (in src points) // - data - filter values sequence // - 'use strict'; - - var FILTER_INFO = require('./resize_filter_info'); // Precision of fixed FP values - - - var FIXED_FRAC_BITS = 14; - - function toFixedPoint(num) { - return Math.round(num * ((1 << FIXED_FRAC_BITS) - 1)); - } - - module.exports = function resizeFilterGen(quality, srcSize, destSize, scale, offset) { - var filterFunction = FILTER_INFO[quality].filter; - var scaleInverted = 1.0 / scale; - var scaleClamped = Math.min(1.0, scale); // For upscale - // Filter window (averaging interval), scaled to src image - - var srcWindow = FILTER_INFO[quality].win / scaleClamped; - var destPixel, srcPixel, srcFirst, srcLast, filterElementSize, floatFilter, fxpFilter, total, pxl, idx, floatVal, filterTotal, filterVal; - var leftNotEmpty, rightNotEmpty, filterShift, filterSize; - var maxFilterElementSize = Math.floor((srcWindow + 1) * 2); - var packedFilter = new Int16Array((maxFilterElementSize + 2) * destSize); - var packedFilterPtr = 0; - var slowCopy = !packedFilter.subarray || !packedFilter.set; // For each destination pixel calculate source range and built filter values - - for (destPixel = 0; destPixel < destSize; destPixel++) { - // Scaling should be done relative to central pixel point - srcPixel = (destPixel + 0.5) * scaleInverted + offset; - srcFirst = Math.max(0, Math.floor(srcPixel - srcWindow)); - srcLast = Math.min(srcSize - 1, Math.ceil(srcPixel + srcWindow)); - filterElementSize = srcLast - srcFirst + 1; - floatFilter = new Float32Array(filterElementSize); - fxpFilter = new Int16Array(filterElementSize); - total = 0.0; // Fill filter values for calculated range - - for (pxl = srcFirst, idx = 0; pxl <= srcLast; pxl++, idx++) { - floatVal = filterFunction((pxl + 0.5 - srcPixel) * scaleClamped); - total += floatVal; - floatFilter[idx] = floatVal; - } // Normalize filter, convert to fixed point and accumulate conversion error - - - filterTotal = 0; - - for (idx = 0; idx < floatFilter.length; idx++) { - filterVal = floatFilter[idx] / total; - filterTotal += filterVal; - fxpFilter[idx] = toFixedPoint(filterVal); - } // Compensate normalization error, to minimize brightness drift - - - fxpFilter[destSize >> 1] += toFixedPoint(1.0 - filterTotal); // - // Now pack filter to useable form - // - // 1. Trim heading and tailing zero values, and compensate shitf/length - // 2. Put all to single array in this format: - // - // [ pos shift, data length, value1, value2, value3, ... ] - // - - leftNotEmpty = 0; - - while (leftNotEmpty < fxpFilter.length && fxpFilter[leftNotEmpty] === 0) { - leftNotEmpty++; - } - - if (leftNotEmpty < fxpFilter.length) { - rightNotEmpty = fxpFilter.length - 1; - - while (rightNotEmpty > 0 && fxpFilter[rightNotEmpty] === 0) { - rightNotEmpty--; - } - - filterShift = srcFirst + leftNotEmpty; - filterSize = rightNotEmpty - leftNotEmpty + 1; - packedFilter[packedFilterPtr++] = filterShift; // shift - - packedFilter[packedFilterPtr++] = filterSize; // size - - if (!slowCopy) { - packedFilter.set(fxpFilter.subarray(leftNotEmpty, rightNotEmpty + 1), packedFilterPtr); - packedFilterPtr += filterSize; - } else { - // fallback for old IE < 11, without subarray/set methods - for (idx = leftNotEmpty; idx <= rightNotEmpty; idx++) { - packedFilter[packedFilterPtr++] = fxpFilter[idx]; - } - } - } else { - // zero data, write header only - packedFilter[packedFilterPtr++] = 0; // shift - - packedFilter[packedFilterPtr++] = 0; // size - } - } - - return packedFilter; - }; - - },{"./resize_filter_info":7}],7:[function(require,module,exports){ +'use strict'; + +var FILTER_INFO = require('./resize_filter_info'); // Precision of fixed FP values + + +var FIXED_FRAC_BITS = 14; + +function toFixedPoint(num) { + return Math.round(num * ((1 << FIXED_FRAC_BITS) - 1)); +} + +module.exports = function resizeFilterGen(quality, srcSize, destSize, scale, offset) { + var filterFunction = FILTER_INFO[quality].filter; + var scaleInverted = 1.0 / scale; + var scaleClamped = Math.min(1.0, scale); // For upscale + // Filter window (averaging interval), scaled to src image + + var srcWindow = FILTER_INFO[quality].win / scaleClamped; + var destPixel, srcPixel, srcFirst, srcLast, filterElementSize, floatFilter, fxpFilter, total, pxl, idx, floatVal, filterTotal, filterVal; + var leftNotEmpty, rightNotEmpty, filterShift, filterSize; + var maxFilterElementSize = Math.floor((srcWindow + 1) * 2); + var packedFilter = new Int16Array((maxFilterElementSize + 2) * destSize); + var packedFilterPtr = 0; + var slowCopy = !packedFilter.subarray || !packedFilter.set; // For each destination pixel calculate source range and built filter values + + for (destPixel = 0; destPixel < destSize; destPixel++) { + // Scaling should be done relative to central pixel point + srcPixel = (destPixel + 0.5) * scaleInverted + offset; + srcFirst = Math.max(0, Math.floor(srcPixel - srcWindow)); + srcLast = Math.min(srcSize - 1, Math.ceil(srcPixel + srcWindow)); + filterElementSize = srcLast - srcFirst + 1; + floatFilter = new Float32Array(filterElementSize); + fxpFilter = new Int16Array(filterElementSize); + total = 0.0; // Fill filter values for calculated range + + for (pxl = srcFirst, idx = 0; pxl <= srcLast; pxl++, idx++) { + floatVal = filterFunction((pxl + 0.5 - srcPixel) * scaleClamped); + total += floatVal; + floatFilter[idx] = floatVal; + } // Normalize filter, convert to fixed point and accumulate conversion error + + + filterTotal = 0; + + for (idx = 0; idx < floatFilter.length; idx++) { + filterVal = floatFilter[idx] / total; + filterTotal += filterVal; + fxpFilter[idx] = toFixedPoint(filterVal); + } // Compensate normalization error, to minimize brightness drift + + + fxpFilter[destSize >> 1] += toFixedPoint(1.0 - filterTotal); // + // Now pack filter to useable form + // + // 1. Trim heading and tailing zero values, and compensate shitf/length + // 2. Put all to single array in this format: + // + // [ pos shift, data length, value1, value2, value3, ... ] + // + + leftNotEmpty = 0; + + while (leftNotEmpty < fxpFilter.length && fxpFilter[leftNotEmpty] === 0) { + leftNotEmpty++; + } + + if (leftNotEmpty < fxpFilter.length) { + rightNotEmpty = fxpFilter.length - 1; + + while (rightNotEmpty > 0 && fxpFilter[rightNotEmpty] === 0) { + rightNotEmpty--; + } + + filterShift = srcFirst + leftNotEmpty; + filterSize = rightNotEmpty - leftNotEmpty + 1; + packedFilter[packedFilterPtr++] = filterShift; // shift + + packedFilter[packedFilterPtr++] = filterSize; // size + + if (!slowCopy) { + packedFilter.set(fxpFilter.subarray(leftNotEmpty, rightNotEmpty + 1), packedFilterPtr); + packedFilterPtr += filterSize; + } else { + // fallback for old IE < 11, without subarray/set methods + for (idx = leftNotEmpty; idx <= rightNotEmpty; idx++) { + packedFilter[packedFilterPtr++] = fxpFilter[idx]; + } + } + } else { + // zero data, write header only + packedFilter[packedFilterPtr++] = 0; // shift + + packedFilter[packedFilterPtr++] = 0; // size + } + } + + return packedFilter; +}; + +},{"./resize_filter_info":7}],7:[function(require,module,exports){ // Filter definitions to build tables for // resizing convolvers. // // Presets for quality 0..3. Filter functions + window size // - 'use strict'; - - module.exports = [{ - // Nearest neibor (Box) - win: 0.5, - filter: function filter(x) { - return x >= -0.5 && x < 0.5 ? 1.0 : 0.0; - } - }, { - // Hamming - win: 1.0, - filter: function filter(x) { - if (x <= -1.0 || x >= 1.0) { - return 0.0; - } - - if (x > -1.19209290E-07 && x < 1.19209290E-07) { - return 1.0; - } - - var xpi = x * Math.PI; - return Math.sin(xpi) / xpi * (0.54 + 0.46 * Math.cos(xpi / 1.0)); - } - }, { - // Lanczos, win = 2 - win: 2.0, - filter: function filter(x) { - if (x <= -2.0 || x >= 2.0) { - return 0.0; - } - - if (x > -1.19209290E-07 && x < 1.19209290E-07) { - return 1.0; - } - - var xpi = x * Math.PI; - return Math.sin(xpi) / xpi * Math.sin(xpi / 2.0) / (xpi / 2.0); - } - }, { - // Lanczos, win = 3 - win: 3.0, - filter: function filter(x) { - if (x <= -3.0 || x >= 3.0) { - return 0.0; - } - - if (x > -1.19209290E-07 && x < 1.19209290E-07) { - return 1.0; - } - - var xpi = x * Math.PI; - return Math.sin(xpi) / xpi * Math.sin(xpi / 3.0) / (xpi / 3.0); - } - }]; - - },{}],8:[function(require,module,exports){ - 'use strict'; - - var createFilters = require('./resize_filter_gen'); - - function resetAlpha(dst, width, height) { - var ptr = 3, - len = width * height * 4 | 0; - - while (ptr < len) { - dst[ptr] = 0xFF; - ptr = ptr + 4 | 0; - } - } - - function asUint8Array(src) { - return new Uint8Array(src.buffer, 0, src.byteLength); - } - - var IS_LE = true; // should not crash everything on module load in old browsers - - try { - IS_LE = new Uint32Array(new Uint8Array([1, 0, 0, 0]).buffer)[0] === 1; - } catch (__) {} - - function copyInt16asLE(src, target, target_offset) { - if (IS_LE) { - target.set(asUint8Array(src), target_offset); - return; - } - - for (var ptr = target_offset, i = 0; i < src.length; i++) { - var data = src[i]; - target[ptr++] = data & 0xFF; - target[ptr++] = data >> 8 & 0xFF; - } - } - - module.exports = function resize_wasm(options) { - var src = options.src; - var srcW = options.width; - var srcH = options.height; - var destW = options.toWidth; - var destH = options.toHeight; - var scaleX = options.scaleX || options.toWidth / options.width; - var scaleY = options.scaleY || options.toHeight / options.height; - var offsetX = options.offsetX || 0.0; - var offsetY = options.offsetY || 0.0; - var dest = options.dest || new Uint8Array(destW * destH * 4); - var quality = typeof options.quality === 'undefined' ? 3 : options.quality; - var alpha = options.alpha || false; - var filtersX = createFilters(quality, srcW, destW, scaleX, offsetX), - filtersY = createFilters(quality, srcH, destH, scaleY, offsetY); // destination is 0 too. - - var src_offset = 0; // buffer between convolve passes - - var tmp_offset = this.__align(src_offset + Math.max(src.byteLength, dest.byteLength)); - - var filtersX_offset = this.__align(tmp_offset + srcH * destW * 4); - - var filtersY_offset = this.__align(filtersX_offset + filtersX.byteLength); - - var alloc_bytes = filtersY_offset + filtersY.byteLength; - - var instance = this.__instance('resize', alloc_bytes); // - // Fill memory block with data to process - // - - - var mem = new Uint8Array(this.__memory.buffer); - var mem32 = new Uint32Array(this.__memory.buffer); // 32-bit copy is much faster in chrome - - var src32 = new Uint32Array(src.buffer); - mem32.set(src32); // We should guarantee LE bytes order. Filters are not big, so - // speed difference is not significant vs direct .set() - - copyInt16asLE(filtersX, mem, filtersX_offset); - copyInt16asLE(filtersY, mem, filtersY_offset); // - // Now call webassembly method - // emsdk does method names with '_' - - var fn = instance.exports.convolveHV || instance.exports._convolveHV; - fn(filtersX_offset, filtersY_offset, tmp_offset, srcW, srcH, destW, destH); // - // Copy data back to typed array - // - // 32-bit copy is much faster in chrome - - var dest32 = new Uint32Array(dest.buffer); - dest32.set(new Uint32Array(this.__memory.buffer, 0, destH * destW)); // That's faster than doing checks in convolver. - // !!! Note, canvas data is not premultipled. We don't need other - // alpha corrections. - - if (!alpha) resetAlpha(dest, destW, destH); - return dest; - }; - - },{"./resize_filter_gen":6}],9:[function(require,module,exports){ - 'use strict'; - - var GC_INTERVAL = 100; - - function Pool(create, idle) { - this.create = create; - this.available = []; - this.acquired = {}; - this.lastId = 1; - this.timeoutId = 0; - this.idle = idle || 2000; - } - - Pool.prototype.acquire = function () { - var _this = this; - - var resource; - - if (this.available.length !== 0) { - resource = this.available.pop(); - } else { - resource = this.create(); - resource.id = this.lastId++; - - resource.release = function () { - return _this.release(resource); - }; - } - - this.acquired[resource.id] = resource; - return resource; - }; - - Pool.prototype.release = function (resource) { - var _this2 = this; - - delete this.acquired[resource.id]; - resource.lastUsed = Date.now(); - this.available.push(resource); - - if (this.timeoutId === 0) { - this.timeoutId = setTimeout(function () { - return _this2.gc(); - }, GC_INTERVAL); - } - }; - - Pool.prototype.gc = function () { - var _this3 = this; - - var now = Date.now(); - this.available = this.available.filter(function (resource) { - if (now - resource.lastUsed > _this3.idle) { - resource.destroy(); - return false; - } - - return true; - }); - - if (this.available.length !== 0) { - this.timeoutId = setTimeout(function () { - return _this3.gc(); - }, GC_INTERVAL); - } else { - this.timeoutId = 0; - } - }; - - module.exports = Pool; - - },{}],10:[function(require,module,exports){ +'use strict'; + +module.exports = [{ + // Nearest neibor (Box) + win: 0.5, + filter: function filter(x) { + return x >= -0.5 && x < 0.5 ? 1.0 : 0.0; + } +}, { + // Hamming + win: 1.0, + filter: function filter(x) { + if (x <= -1.0 || x >= 1.0) { + return 0.0; + } + + if (x > -1.19209290E-07 && x < 1.19209290E-07) { + return 1.0; + } + + var xpi = x * Math.PI; + return Math.sin(xpi) / xpi * (0.54 + 0.46 * Math.cos(xpi / 1.0)); + } +}, { + // Lanczos, win = 2 + win: 2.0, + filter: function filter(x) { + if (x <= -2.0 || x >= 2.0) { + return 0.0; + } + + if (x > -1.19209290E-07 && x < 1.19209290E-07) { + return 1.0; + } + + var xpi = x * Math.PI; + return Math.sin(xpi) / xpi * Math.sin(xpi / 2.0) / (xpi / 2.0); + } +}, { + // Lanczos, win = 3 + win: 3.0, + filter: function filter(x) { + if (x <= -3.0 || x >= 3.0) { + return 0.0; + } + + if (x > -1.19209290E-07 && x < 1.19209290E-07) { + return 1.0; + } + + var xpi = x * Math.PI; + return Math.sin(xpi) / xpi * Math.sin(xpi / 3.0) / (xpi / 3.0); + } +}]; + +},{}],8:[function(require,module,exports){ +'use strict'; + +var createFilters = require('./resize_filter_gen'); + +function resetAlpha(dst, width, height) { + var ptr = 3, + len = width * height * 4 | 0; + + while (ptr < len) { + dst[ptr] = 0xFF; + ptr = ptr + 4 | 0; + } +} + +function asUint8Array(src) { + return new Uint8Array(src.buffer, 0, src.byteLength); +} + +var IS_LE = true; // should not crash everything on module load in old browsers + +try { + IS_LE = new Uint32Array(new Uint8Array([1, 0, 0, 0]).buffer)[0] === 1; +} catch (__) {} + +function copyInt16asLE(src, target, target_offset) { + if (IS_LE) { + target.set(asUint8Array(src), target_offset); + return; + } + + for (var ptr = target_offset, i = 0; i < src.length; i++) { + var data = src[i]; + target[ptr++] = data & 0xFF; + target[ptr++] = data >> 8 & 0xFF; + } +} + +module.exports = function resize_wasm(options) { + var src = options.src; + var srcW = options.width; + var srcH = options.height; + var destW = options.toWidth; + var destH = options.toHeight; + var scaleX = options.scaleX || options.toWidth / options.width; + var scaleY = options.scaleY || options.toHeight / options.height; + var offsetX = options.offsetX || 0.0; + var offsetY = options.offsetY || 0.0; + var dest = options.dest || new Uint8Array(destW * destH * 4); + var quality = typeof options.quality === 'undefined' ? 3 : options.quality; + var alpha = options.alpha || false; + var filtersX = createFilters(quality, srcW, destW, scaleX, offsetX), + filtersY = createFilters(quality, srcH, destH, scaleY, offsetY); // destination is 0 too. + + var src_offset = 0; // buffer between convolve passes + + var tmp_offset = this.__align(src_offset + Math.max(src.byteLength, dest.byteLength)); + + var filtersX_offset = this.__align(tmp_offset + srcH * destW * 4); + + var filtersY_offset = this.__align(filtersX_offset + filtersX.byteLength); + + var alloc_bytes = filtersY_offset + filtersY.byteLength; + + var instance = this.__instance('resize', alloc_bytes); // + // Fill memory block with data to process + // + + + var mem = new Uint8Array(this.__memory.buffer); + var mem32 = new Uint32Array(this.__memory.buffer); // 32-bit copy is much faster in chrome + + var src32 = new Uint32Array(src.buffer); + mem32.set(src32); // We should guarantee LE bytes order. Filters are not big, so + // speed difference is not significant vs direct .set() + + copyInt16asLE(filtersX, mem, filtersX_offset); + copyInt16asLE(filtersY, mem, filtersY_offset); // + // Now call webassembly method + // emsdk does method names with '_' + + var fn = instance.exports.convolveHV || instance.exports._convolveHV; + fn(filtersX_offset, filtersY_offset, tmp_offset, srcW, srcH, destW, destH); // + // Copy data back to typed array + // + // 32-bit copy is much faster in chrome + + var dest32 = new Uint32Array(dest.buffer); + dest32.set(new Uint32Array(this.__memory.buffer, 0, destH * destW)); // That's faster than doing checks in convolver. + // !!! Note, canvas data is not premultipled. We don't need other + // alpha corrections. + + if (!alpha) resetAlpha(dest, destW, destH); + return dest; +}; + +},{"./resize_filter_gen":6}],9:[function(require,module,exports){ +'use strict'; + +var GC_INTERVAL = 100; + +function Pool(create, idle) { + this.create = create; + this.available = []; + this.acquired = {}; + this.lastId = 1; + this.timeoutId = 0; + this.idle = idle || 2000; +} + +Pool.prototype.acquire = function () { + var _this = this; + + var resource; + + if (this.available.length !== 0) { + resource = this.available.pop(); + } else { + resource = this.create(); + resource.id = this.lastId++; + + resource.release = function () { + return _this.release(resource); + }; + } + + this.acquired[resource.id] = resource; + return resource; +}; + +Pool.prototype.release = function (resource) { + var _this2 = this; + + delete this.acquired[resource.id]; + resource.lastUsed = Date.now(); + this.available.push(resource); + + if (this.timeoutId === 0) { + this.timeoutId = setTimeout(function () { + return _this2.gc(); + }, GC_INTERVAL); + } +}; + +Pool.prototype.gc = function () { + var _this3 = this; + + var now = Date.now(); + this.available = this.available.filter(function (resource) { + if (now - resource.lastUsed > _this3.idle) { + resource.destroy(); + return false; + } + + return true; + }); + + if (this.available.length !== 0) { + this.timeoutId = setTimeout(function () { + return _this3.gc(); + }, GC_INTERVAL); + } else { + this.timeoutId = 0; + } +}; + +module.exports = Pool; + +},{}],10:[function(require,module,exports){ // Add intermediate resizing steps when scaling down by a very large factor. // // For example, when resizing 10000x10000 down to 10x10, it'll resize it to @@ -618,640 +597,646 @@ THE SOFTWARE. */ // Also, adding intermediate steps can speed up processing if we use lower // quality algorithms for first stages. // - 'use strict'; // min size = 0 results in infinite loop, +'use strict'; // min size = 0 results in infinite loop, // min size = 1 can consume large amount of memory - - var MIN_INNER_TILE_SIZE = 2; - - module.exports = function createStages(fromWidth, fromHeight, toWidth, toHeight, srcTileSize, destTileBorder) { - var scaleX = toWidth / fromWidth; - var scaleY = toHeight / fromHeight; // derived from createRegions equation: - // innerTileWidth = pixelFloor(srcTileSize * scaleX) - 2 * destTileBorder; - - var minScale = (2 * destTileBorder + MIN_INNER_TILE_SIZE + 1) / srcTileSize; // refuse to scale image multiple times by less than twice each time, - // it could only happen because of invalid options - - if (minScale > 0.5) return [[toWidth, toHeight]]; - var stageCount = Math.ceil(Math.log(Math.min(scaleX, scaleY)) / Math.log(minScale)); // no additional resizes are necessary, - // stageCount can be zero or be negative when enlarging the image - - if (stageCount <= 1) return [[toWidth, toHeight]]; - var result = []; - - for (var i = 0; i < stageCount; i++) { - var width = Math.round(Math.pow(Math.pow(fromWidth, stageCount - i - 1) * Math.pow(toWidth, i + 1), 1 / stageCount)); - var height = Math.round(Math.pow(Math.pow(fromHeight, stageCount - i - 1) * Math.pow(toHeight, i + 1), 1 / stageCount)); - result.push([width, height]); - } - - return result; - }; - - },{}],11:[function(require,module,exports){ + +var MIN_INNER_TILE_SIZE = 2; + +module.exports = function createStages(fromWidth, fromHeight, toWidth, toHeight, srcTileSize, destTileBorder) { + var scaleX = toWidth / fromWidth; + var scaleY = toHeight / fromHeight; // derived from createRegions equation: + // innerTileWidth = pixelFloor(srcTileSize * scaleX) - 2 * destTileBorder; + + var minScale = (2 * destTileBorder + MIN_INNER_TILE_SIZE + 1) / srcTileSize; // refuse to scale image multiple times by less than twice each time, + // it could only happen because of invalid options + + if (minScale > 0.5) return [[toWidth, toHeight]]; + var stageCount = Math.ceil(Math.log(Math.min(scaleX, scaleY)) / Math.log(minScale)); // no additional resizes are necessary, + // stageCount can be zero or be negative when enlarging the image + + if (stageCount <= 1) return [[toWidth, toHeight]]; + var result = []; + + for (var i = 0; i < stageCount; i++) { + var width = Math.round(Math.pow(Math.pow(fromWidth, stageCount - i - 1) * Math.pow(toWidth, i + 1), 1 / stageCount)); + var height = Math.round(Math.pow(Math.pow(fromHeight, stageCount - i - 1) * Math.pow(toHeight, i + 1), 1 / stageCount)); + result.push([width, height]); + } + + return result; +}; + +},{}],11:[function(require,module,exports){ // Split original image into multiple 1024x1024 chunks to reduce memory usage // (images have to be unpacked into typed arrays for resizing) and allow // parallel processing of multiple tiles at a time. // - 'use strict'; - /* - * pixelFloor and pixelCeil are modified versions of Math.floor and Math.ceil - * functions which take into account floating point arithmetic errors. - * Those errors can cause undesired increments/decrements of sizes and offsets: - * Math.ceil(36 / (36 / 500)) = 501 - * pixelCeil(36 / (36 / 500)) = 500 - */ - - var PIXEL_EPSILON = 1e-5; - - function pixelFloor(x) { - var nearest = Math.round(x); - - if (Math.abs(x - nearest) < PIXEL_EPSILON) { - return nearest; - } - - return Math.floor(x); - } - - function pixelCeil(x) { - var nearest = Math.round(x); - - if (Math.abs(x - nearest) < PIXEL_EPSILON) { - return nearest; - } - - return Math.ceil(x); - } - - module.exports = function createRegions(options) { - var scaleX = options.toWidth / options.width; - var scaleY = options.toHeight / options.height; - var innerTileWidth = pixelFloor(options.srcTileSize * scaleX) - 2 * options.destTileBorder; - var innerTileHeight = pixelFloor(options.srcTileSize * scaleY) - 2 * options.destTileBorder; // prevent infinite loop, this should never happen - - if (innerTileWidth < 1 || innerTileHeight < 1) { - throw new Error('Internal error in pica: target tile width/height is too small.'); - } - - var x, y; - var innerX, innerY, toTileWidth, toTileHeight; - var tiles = []; - var tile; // we go top-to-down instead of left-to-right to make image displayed from top to - // doesn in the browser - - for (innerY = 0; innerY < options.toHeight; innerY += innerTileHeight) { - for (innerX = 0; innerX < options.toWidth; innerX += innerTileWidth) { - x = innerX - options.destTileBorder; - - if (x < 0) { - x = 0; - } - - toTileWidth = innerX + innerTileWidth + options.destTileBorder - x; - - if (x + toTileWidth >= options.toWidth) { - toTileWidth = options.toWidth - x; - } - - y = innerY - options.destTileBorder; - - if (y < 0) { - y = 0; - } - - toTileHeight = innerY + innerTileHeight + options.destTileBorder - y; - - if (y + toTileHeight >= options.toHeight) { - toTileHeight = options.toHeight - y; - } - - tile = { - toX: x, - toY: y, - toWidth: toTileWidth, - toHeight: toTileHeight, - toInnerX: innerX, - toInnerY: innerY, - toInnerWidth: innerTileWidth, - toInnerHeight: innerTileHeight, - offsetX: x / scaleX - pixelFloor(x / scaleX), - offsetY: y / scaleY - pixelFloor(y / scaleY), - scaleX: scaleX, - scaleY: scaleY, - x: pixelFloor(x / scaleX), - y: pixelFloor(y / scaleY), - width: pixelCeil(toTileWidth / scaleX), - height: pixelCeil(toTileHeight / scaleY) - }; - tiles.push(tile); - } - } - - return tiles; - }; - - },{}],12:[function(require,module,exports){ - 'use strict'; - - function objClass(obj) { - return Object.prototype.toString.call(obj); - } - - module.exports.isCanvas = function isCanvas(element) { - //return (element.nodeName && element.nodeName.toLowerCase() === 'canvas') || - var cname = objClass(element); - return cname === '[object HTMLCanvasElement]' - /* browser */ - || cname === '[object Canvas]' - /* node-canvas */ - ; - }; - - module.exports.isImage = function isImage(element) { - //return element.nodeName && element.nodeName.toLowerCase() === 'img'; - return objClass(element) === '[object HTMLImageElement]'; - }; - - module.exports.limiter = function limiter(concurrency) { - var active = 0, - queue = []; - - function roll() { - if (active < concurrency && queue.length) { - active++; - queue.shift()(); - } - } - - return function limit(fn) { - return new Promise(function (resolve, reject) { - queue.push(function () { - fn().then(function (result) { - resolve(result); - active--; - roll(); - }, function (err) { - reject(err); - active--; - roll(); - }); - }); - roll(); - }); - }; - }; - - module.exports.cib_quality_name = function cib_quality_name(num) { - switch (num) { - case 0: - return 'pixelated'; - - case 1: - return 'low'; - - case 2: - return 'medium'; - } - - return 'high'; - }; - - module.exports.cib_support = function cib_support() { - return Promise.resolve().then(function () { - if (typeof createImageBitmap === 'undefined' || typeof document === 'undefined') { - return false; - } - - var c = document.createElement('canvas'); - c.width = 100; - c.height = 100; - return createImageBitmap(c, 0, 0, 100, 100, { - resizeWidth: 10, - resizeHeight: 10, - resizeQuality: 'high' - }).then(function (bitmap) { - var status = bitmap.width === 10; // Branch below is filtered on upper level. We do not call resize - // detection for basic ImageBitmap. - // - // https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap - // old Crome 51 has ImageBitmap without .close(). Then this code - // will throw and return 'false' as expected. - // - - bitmap.close(); - c = null; - return status; - }); - }).catch(function () { - return false; - }); - }; - - },{}],13:[function(require,module,exports){ +'use strict'; +/* + * pixelFloor and pixelCeil are modified versions of Math.floor and Math.ceil + * functions which take into account floating point arithmetic errors. + * Those errors can cause undesired increments/decrements of sizes and offsets: + * Math.ceil(36 / (36 / 500)) = 501 + * pixelCeil(36 / (36 / 500)) = 500 + */ + +var PIXEL_EPSILON = 1e-5; + +function pixelFloor(x) { + var nearest = Math.round(x); + + if (Math.abs(x - nearest) < PIXEL_EPSILON) { + return nearest; + } + + return Math.floor(x); +} + +function pixelCeil(x) { + var nearest = Math.round(x); + + if (Math.abs(x - nearest) < PIXEL_EPSILON) { + return nearest; + } + + return Math.ceil(x); +} + +module.exports = function createRegions(options) { + var scaleX = options.toWidth / options.width; + var scaleY = options.toHeight / options.height; + var innerTileWidth = pixelFloor(options.srcTileSize * scaleX) - 2 * options.destTileBorder; + var innerTileHeight = pixelFloor(options.srcTileSize * scaleY) - 2 * options.destTileBorder; // prevent infinite loop, this should never happen + + if (innerTileWidth < 1 || innerTileHeight < 1) { + throw new Error('Internal error in pica: target tile width/height is too small.'); + } + + var x, y; + var innerX, innerY, toTileWidth, toTileHeight; + var tiles = []; + var tile; // we go top-to-down instead of left-to-right to make image displayed from top to + // doesn in the browser + + for (innerY = 0; innerY < options.toHeight; innerY += innerTileHeight) { + for (innerX = 0; innerX < options.toWidth; innerX += innerTileWidth) { + x = innerX - options.destTileBorder; + + if (x < 0) { + x = 0; + } + + toTileWidth = innerX + innerTileWidth + options.destTileBorder - x; + + if (x + toTileWidth >= options.toWidth) { + toTileWidth = options.toWidth - x; + } + + y = innerY - options.destTileBorder; + + if (y < 0) { + y = 0; + } + + toTileHeight = innerY + innerTileHeight + options.destTileBorder - y; + + if (y + toTileHeight >= options.toHeight) { + toTileHeight = options.toHeight - y; + } + + tile = { + toX: x, + toY: y, + toWidth: toTileWidth, + toHeight: toTileHeight, + toInnerX: innerX, + toInnerY: innerY, + toInnerWidth: innerTileWidth, + toInnerHeight: innerTileHeight, + offsetX: x / scaleX - pixelFloor(x / scaleX), + offsetY: y / scaleY - pixelFloor(y / scaleY), + scaleX: scaleX, + scaleY: scaleY, + x: pixelFloor(x / scaleX), + y: pixelFloor(y / scaleY), + width: pixelCeil(toTileWidth / scaleX), + height: pixelCeil(toTileHeight / scaleY) + }; + tiles.push(tile); + } + } + + return tiles; +}; + +},{}],12:[function(require,module,exports){ +'use strict'; + +function objClass(obj) { + return Object.prototype.toString.call(obj); +} + +module.exports.isCanvas = function isCanvas(element) { + //return (element.nodeName && element.nodeName.toLowerCase() === 'canvas') || + var cname = objClass(element); + return cname === '[object HTMLCanvasElement]' + /* browser */ + || cname === '[object Canvas]' + /* node-canvas */ + ; +}; + +module.exports.isImage = function isImage(element) { + //return element.nodeName && element.nodeName.toLowerCase() === 'img'; + return objClass(element) === '[object HTMLImageElement]'; +}; + +module.exports.limiter = function limiter(concurrency) { + var active = 0, + queue = []; + + function roll() { + if (active < concurrency && queue.length) { + active++; + queue.shift()(); + } + } + + return function limit(fn) { + return new Promise(function (resolve, reject) { + queue.push(function () { + fn().then(function (result) { + resolve(result); + active--; + roll(); + }, function (err) { + reject(err); + active--; + roll(); + }); + }); + roll(); + }); + }; +}; + +module.exports.cib_quality_name = function cib_quality_name(num) { + switch (num) { + case 0: + return 'pixelated'; + + case 1: + return 'low'; + + case 2: + return 'medium'; + } + + return 'high'; +}; + +module.exports.cib_support = function cib_support() { + return Promise.resolve().then(function () { + if (typeof createImageBitmap === 'undefined' || typeof document === 'undefined') { + return false; + } + + var c = document.createElement('canvas'); + c.width = 100; + c.height = 100; + return createImageBitmap(c, 0, 0, 100, 100, { + resizeWidth: 10, + resizeHeight: 10, + resizeQuality: 'high' + }).then(function (bitmap) { + var status = bitmap.width === 10; // Branch below is filtered on upper level. We do not call resize + // detection for basic ImageBitmap. + // + // https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap + // old Crome 51 has ImageBitmap without .close(). Then this code + // will throw and return 'false' as expected. + // + + bitmap.close(); + c = null; + return status; + }); + })["catch"](function () { + return false; + }); +}; + +},{}],13:[function(require,module,exports){ // Web Worker wrapper for image resize function - 'use strict'; - - module.exports = function () { - var MathLib = require('./mathlib'); - - var mathLib; - /* eslint-disable no-undef */ - - onmessage = function onmessage(ev) { - var opts = ev.data.opts; - if (!mathLib) mathLib = new MathLib(ev.data.features); // Use multimath's sync auto-init. Avoid Promise use in old browsers, - // because polyfills are not propagated to webworker. - - var result = mathLib.resizeAndUnsharp(opts); - postMessage({ - result: result - }, [result.buffer]); - }; - }; - - },{"./mathlib":1}],14:[function(require,module,exports){ +'use strict'; + +module.exports = function () { + var MathLib = require('./mathlib'); + + var mathLib; + /* eslint-disable no-undef */ + + onmessage = function onmessage(ev) { + var opts = ev.data.opts; + if (!mathLib) mathLib = new MathLib(ev.data.features); // Use multimath's sync auto-init. Avoid Promise use in old browsers, + // because polyfills are not propagated to webworker. + + var result = mathLib.resizeAndUnsharp(opts); + postMessage({ + result: result + }, [result.buffer]); + }; +}; + +},{"./mathlib":1}],14:[function(require,module,exports){ // Calculate Gaussian blur of an image using IIR filter // The method is taken from Intel's white paper and code example attached to it: // https://software.intel.com/en-us/articles/iir-gaussian-blur-filter // -implementation-using-intel-advanced-vector-extensions - - var a0, a1, a2, a3, b1, b2, left_corner, right_corner; - - function gaussCoef(sigma) { - if (sigma < 0.5) { - sigma = 0.5; - } - - var a = Math.exp(0.726 * 0.726) / sigma, - g1 = Math.exp(-a), - g2 = Math.exp(-2 * a), - k = (1 - g1) * (1 - g1) / (1 + 2 * a * g1 - g2); - - a0 = k; - a1 = k * (a - 1) * g1; - a2 = k * (a + 1) * g1; - a3 = -k * g2; - b1 = 2 * g1; - b2 = -g2; - left_corner = (a0 + a1) / (1 - b1 - b2); - right_corner = (a2 + a3) / (1 - b1 - b2); - - // Attempt to force type to FP32. - return new Float32Array([ a0, a1, a2, a3, b1, b2, left_corner, right_corner ]); - } - - function convolveMono16(src, out, line, coeff, width, height) { - // takes src image and writes the blurred and transposed result into out - - var prev_src, curr_src, curr_out, prev_out, prev_prev_out; - var src_index, out_index, line_index; - var i, j; - var coeff_a0, coeff_a1, coeff_b1, coeff_b2; - - for (i = 0; i < height; i++) { - src_index = i * width; - out_index = i; - line_index = 0; - - // left to right - prev_src = src[src_index]; - prev_prev_out = prev_src * coeff[6]; - prev_out = prev_prev_out; - - coeff_a0 = coeff[0]; - coeff_a1 = coeff[1]; - coeff_b1 = coeff[4]; - coeff_b2 = coeff[5]; - - for (j = 0; j < width; j++) { - curr_src = src[src_index]; - - curr_out = curr_src * coeff_a0 + - prev_src * coeff_a1 + - prev_out * coeff_b1 + - prev_prev_out * coeff_b2; - - prev_prev_out = prev_out; - prev_out = curr_out; - prev_src = curr_src; - - line[line_index] = prev_out; - line_index++; - src_index++; - } - - src_index--; - line_index--; - out_index += height * (width - 1); - - // right to left - prev_src = src[src_index]; - prev_prev_out = prev_src * coeff[7]; - prev_out = prev_prev_out; - curr_src = prev_src; - - coeff_a0 = coeff[2]; - coeff_a1 = coeff[3]; - - for (j = width - 1; j >= 0; j--) { - curr_out = curr_src * coeff_a0 + - prev_src * coeff_a1 + - prev_out * coeff_b1 + - prev_prev_out * coeff_b2; - - prev_prev_out = prev_out; - prev_out = curr_out; - - prev_src = curr_src; - curr_src = src[src_index]; - - out[out_index] = line[line_index] + prev_out; - - src_index--; - line_index--; - out_index -= height; - } - } - } - - - function blurMono16(src, width, height, radius) { - // Quick exit on zero radius - if (!radius) { return; } - - var out = new Uint16Array(src.length), - tmp_line = new Float32Array(Math.max(width, height)); - - var coeff = gaussCoef(radius); - - convolveMono16(src, out, tmp_line, coeff, width, height, radius); - convolveMono16(out, src, tmp_line, coeff, height, width, radius); - } - - module.exports = blurMono16; - - },{}],15:[function(require,module,exports){ - if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } - - },{}],16:[function(require,module,exports){ - 'use strict'; - - - var assign = require('object-assign'); - var base64decode = require('./lib/base64decode'); - var hasWebAssembly = require('./lib/wa_detect'); - - - var DEFAULT_OPTIONS = { - js: true, - wasm: true - }; - - - function MultiMath(options) { - if (!(this instanceof MultiMath)) return new MultiMath(options); - - var opts = assign({}, DEFAULT_OPTIONS, options || {}); - - this.options = opts; - - this.__cache = {}; - this.has_wasm = hasWebAssembly(); - - this.__init_promise = null; - this.__modules = opts.modules || {}; - this.__memory = null; - this.__wasm = {}; - - this.__isLE = ((new Uint32Array((new Uint8Array([ 1, 0, 0, 0 ])).buffer))[0] === 1); - - if (!this.options.js && !this.options.wasm) { - throw new Error('mathlib: at least "js" or "wasm" should be enabled'); - } - } - - - MultiMath.prototype.use = function (module) { - this.__modules[module.name] = module; - - // Pin the best possible implementation - if (!this.has_wasm || !this.options.wasm || !module.wasm_fn) { - this[module.name] = module.fn; - } else { - this[module.name] = module.wasm_fn; - } - - return this; - }; - - - MultiMath.prototype.init = function () { - if (this.__init_promise) return this.__init_promise; - - if (!this.options.js && this.options.wasm && !this.has_wasm) { - return Promise.reject(new Error('mathlib: only "wasm" was enabled, but it\'s not supported')); - } - - var self = this; - - this.__init_promise = Promise.all(Object.keys(self.__modules).map(function (name) { - var module = self.__modules[name]; - - if (!self.has_wasm || !self.options.wasm || !module.wasm_fn) return null; - - // If already compiled - exit - if (self.__wasm[name]) return null; - - // Compile wasm source - return WebAssembly.compile(self.__base64decode(module.wasm_src)) - .then(function (m) { self.__wasm[name] = m; }); - })) - .then(function () { return self; }); - - return this.__init_promise; - }; +var a0, a1, a2, a3, b1, b2, left_corner, right_corner; -//////////////////////////////////////////////////////////////////////////////// -// Methods below are for internal use from plugins +function gaussCoef(sigma) { + if (sigma < 0.5) { + sigma = 0.5; + } + var a = Math.exp(0.726 * 0.726) / sigma, + g1 = Math.exp(-a), + g2 = Math.exp(-2 * a), + k = (1 - g1) * (1 - g1) / (1 + 2 * a * g1 - g2); -// Simple decode base64 to typed array. Useful to load embedded webassembly -// code. You probably don't need to call this method directly. -// - MultiMath.prototype.__base64decode = base64decode; + a0 = k; + a1 = k * (a - 1) * g1; + a2 = k * (a + 1) * g1; + a3 = -k * g2; + b1 = 2 * g1; + b2 = -g2; + left_corner = (a0 + a1) / (1 - b1 - b2); + right_corner = (a2 + a3) / (1 - b1 - b2); + // Attempt to force type to FP32. + return new Float32Array([ a0, a1, a2, a3, b1, b2, left_corner, right_corner ]); +} -// Increase current memory to include specified number of bytes. Do nothing if -// size is already ok. You probably don't need to call this method directly, -// because it will be invoked from `.__instance()`. -// - MultiMath.prototype.__reallocate = function mem_grow_to(bytes) { - if (!this.__memory) { - this.__memory = new WebAssembly.Memory({ - initial: Math.ceil(bytes / (64 * 1024)) - }); - return this.__memory; - } - - var mem_size = this.__memory.buffer.byteLength; - - if (mem_size < bytes) { - this.__memory.grow(Math.ceil((bytes - mem_size) / (64 * 1024))); - } - - return this.__memory; - }; +function convolveMono16(src, out, line, coeff, width, height) { + // takes src image and writes the blurred and transposed result into out + var prev_src, curr_src, curr_out, prev_out, prev_prev_out; + var src_index, out_index, line_index; + var i, j; + var coeff_a0, coeff_a1, coeff_b1, coeff_b2; -// Returns instantinated webassembly item by name, with specified memory size -// and environment. -// - use cache if available -// - do sync module init, if async init was not called earlier -// - allocate memory if not enougth -// - can export functions to webassembly via "env_extra", -// for example, { exp: Math.exp } -// - MultiMath.prototype.__instance = function instance(name, memsize, env_extra) { - if (memsize) this.__reallocate(memsize); - - // If .init() was not called, do sync compile - if (!this.__wasm[name]) { - var module = this.__modules[name]; - this.__wasm[name] = new WebAssembly.Module(this.__base64decode(module.wasm_src)); - } - - if (!this.__cache[name]) { - var env_base = { - memoryBase: 0, - memory: this.__memory, - tableBase: 0, - table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' }) - }; - - this.__cache[name] = new WebAssembly.Instance(this.__wasm[name], { - env: assign(env_base, env_extra || {}) - }); - } - - return this.__cache[name]; - }; + for (i = 0; i < height; i++) { + src_index = i * width; + out_index = i; + line_index = 0; + // left to right + prev_src = src[src_index]; + prev_prev_out = prev_src * coeff[6]; + prev_out = prev_prev_out; -// Helper to calculate memory aligh for pointers. Webassembly does not require -// this, but you may wish to experiment. Default base = 8; -// - MultiMath.prototype.__align = function align(number, base) { - base = base || 8; - var reminder = number % base; - return number + (reminder ? base - reminder : 0); - }; - - - module.exports = MultiMath; - - },{"./lib/base64decode":17,"./lib/wa_detect":23,"object-assign":24}],17:[function(require,module,exports){ -// base64 decode str -> Uint8Array, to load WA modules -// - 'use strict'; - - - var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - - module.exports = function base64decode(str) { - var input = str.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan - max = input.length; - - var out = new Uint8Array((max * 3) >> 2); - - // Collect by 6*4 bits (3 bytes) - - var bits = 0; - var ptr = 0; - - for (var idx = 0; idx < max; idx++) { - if ((idx % 4 === 0) && idx) { - out[ptr++] = (bits >> 16) & 0xFF; - out[ptr++] = (bits >> 8) & 0xFF; - out[ptr++] = bits & 0xFF; - } - - bits = (bits << 6) | BASE64_MAP.indexOf(input.charAt(idx)); - } - - // Dump tail - - var tailbits = (max % 4) * 6; - - if (tailbits === 0) { - out[ptr++] = (bits >> 16) & 0xFF; - out[ptr++] = (bits >> 8) & 0xFF; - out[ptr++] = bits & 0xFF; - } else if (tailbits === 18) { - out[ptr++] = (bits >> 10) & 0xFF; - out[ptr++] = (bits >> 2) & 0xFF; - } else if (tailbits === 12) { - out[ptr++] = (bits >> 4) & 0xFF; - } - - return out; - }; - - },{}],18:[function(require,module,exports){ -// Calculates 16-bit precision HSL lightness from 8-bit rgba buffer -// - 'use strict'; - - - module.exports = function hsl_l16_js(img, width, height) { - var size = width * height; - var out = new Uint16Array(size); - var r, g, b, min, max; - for (var i = 0; i < size; i++) { - r = img[4 * i]; - g = img[4 * i + 1]; - b = img[4 * i + 2]; - max = (r >= g && r >= b) ? r : (g >= b && g >= r) ? g : b; - min = (r <= g && r <= b) ? r : (g <= b && g <= r) ? g : b; - out[i] = (max + min) * 257 >> 1; - } - return out; - }; - - },{}],19:[function(require,module,exports){ - 'use strict'; - - module.exports = { - name: 'unsharp_mask', - fn: require('./unsharp_mask'), - wasm_fn: require('./unsharp_mask_wasm'), - wasm_src: require('./unsharp_mask_wasm_base64') - }; - - },{"./unsharp_mask":20,"./unsharp_mask_wasm":21,"./unsharp_mask_wasm_base64":22}],20:[function(require,module,exports){ + coeff_a0 = coeff[0]; + coeff_a1 = coeff[1]; + coeff_b1 = coeff[4]; + coeff_b2 = coeff[5]; + + for (j = 0; j < width; j++) { + curr_src = src[src_index]; + + curr_out = curr_src * coeff_a0 + + prev_src * coeff_a1 + + prev_out * coeff_b1 + + prev_prev_out * coeff_b2; + + prev_prev_out = prev_out; + prev_out = curr_out; + prev_src = curr_src; + + line[line_index] = prev_out; + line_index++; + src_index++; + } + + src_index--; + line_index--; + out_index += height * (width - 1); + + // right to left + prev_src = src[src_index]; + prev_prev_out = prev_src * coeff[7]; + prev_out = prev_prev_out; + curr_src = prev_src; + + coeff_a0 = coeff[2]; + coeff_a1 = coeff[3]; + + for (j = width - 1; j >= 0; j--) { + curr_out = curr_src * coeff_a0 + + prev_src * coeff_a1 + + prev_out * coeff_b1 + + prev_prev_out * coeff_b2; + + prev_prev_out = prev_out; + prev_out = curr_out; + + prev_src = curr_src; + curr_src = src[src_index]; + + out[out_index] = line[line_index] + prev_out; + + src_index--; + line_index--; + out_index -= height; + } + } +} + + +function blurMono16(src, width, height, radius) { + // Quick exit on zero radius + if (!radius) { return; } + + var out = new Uint16Array(src.length), + tmp_line = new Float32Array(Math.max(width, height)); + + var coeff = gaussCoef(radius); + + convolveMono16(src, out, tmp_line, coeff, width, height, radius); + convolveMono16(out, src, tmp_line, coeff, height, width, radius); +} + +module.exports = blurMono16; + +},{}],15:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} + +},{}],16:[function(require,module,exports){ +'use strict'; + + +var assign = require('object-assign'); +var base64decode = require('./lib/base64decode'); +var hasWebAssembly = require('./lib/wa_detect'); + + +var DEFAULT_OPTIONS = { + js: true, + wasm: true +}; + + +function MultiMath(options) { + if (!(this instanceof MultiMath)) return new MultiMath(options); + + var opts = assign({}, DEFAULT_OPTIONS, options || {}); + + this.options = opts; + + this.__cache = {}; + + this.__init_promise = null; + this.__modules = opts.modules || {}; + this.__memory = null; + this.__wasm = {}; + + this.__isLE = ((new Uint32Array((new Uint8Array([ 1, 0, 0, 0 ])).buffer))[0] === 1); + + if (!this.options.js && !this.options.wasm) { + throw new Error('mathlib: at least "js" or "wasm" should be enabled'); + } +} + + +MultiMath.prototype.has_wasm = hasWebAssembly; + + +MultiMath.prototype.use = function (module) { + this.__modules[module.name] = module; + + // Pin the best possible implementation + if (this.options.wasm && this.has_wasm() && module.wasm_fn) { + this[module.name] = module.wasm_fn; + } else { + this[module.name] = module.fn; + } + + return this; +}; + + +MultiMath.prototype.init = function () { + if (this.__init_promise) return this.__init_promise; + + if (!this.options.js && this.options.wasm && !this.has_wasm()) { + return Promise.reject(new Error('mathlib: only "wasm" was enabled, but it\'s not supported')); + } + + var self = this; + + this.__init_promise = Promise.all(Object.keys(self.__modules).map(function (name) { + var module = self.__modules[name]; + + if (!self.options.wasm || !self.has_wasm() || !module.wasm_fn) return null; + + // If already compiled - exit + if (self.__wasm[name]) return null; + + // Compile wasm source + return WebAssembly.compile(self.__base64decode(module.wasm_src)) + .then(function (m) { self.__wasm[name] = m; }); + })) + .then(function () { return self; }); + + return this.__init_promise; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Methods below are for internal use from plugins + + +// Simple decode base64 to typed array. Useful to load embedded webassembly +// code. You probably don't need to call this method directly. +// +MultiMath.prototype.__base64decode = base64decode; + + +// Increase current memory to include specified number of bytes. Do nothing if +// size is already ok. You probably don't need to call this method directly, +// because it will be invoked from `.__instance()`. +// +MultiMath.prototype.__reallocate = function mem_grow_to(bytes) { + if (!this.__memory) { + this.__memory = new WebAssembly.Memory({ + initial: Math.ceil(bytes / (64 * 1024)) + }); + return this.__memory; + } + + var mem_size = this.__memory.buffer.byteLength; + + if (mem_size < bytes) { + this.__memory.grow(Math.ceil((bytes - mem_size) / (64 * 1024))); + } + + return this.__memory; +}; + + +// Returns instantinated webassembly item by name, with specified memory size +// and environment. +// - use cache if available +// - do sync module init, if async init was not called earlier +// - allocate memory if not enougth +// - can export functions to webassembly via "env_extra", +// for example, { exp: Math.exp } +// +MultiMath.prototype.__instance = function instance(name, memsize, env_extra) { + if (memsize) this.__reallocate(memsize); + + // If .init() was not called, do sync compile + if (!this.__wasm[name]) { + var module = this.__modules[name]; + this.__wasm[name] = new WebAssembly.Module(this.__base64decode(module.wasm_src)); + } + + if (!this.__cache[name]) { + var env_base = { + memoryBase: 0, + memory: this.__memory, + tableBase: 0, + table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' }) + }; + + this.__cache[name] = new WebAssembly.Instance(this.__wasm[name], { + env: assign(env_base, env_extra || {}) + }); + } + + return this.__cache[name]; +}; + + +// Helper to calculate memory aligh for pointers. Webassembly does not require +// this, but you may wish to experiment. Default base = 8; +// +MultiMath.prototype.__align = function align(number, base) { + base = base || 8; + var reminder = number % base; + return number + (reminder ? base - reminder : 0); +}; + + +module.exports = MultiMath; + +},{"./lib/base64decode":17,"./lib/wa_detect":23,"object-assign":24}],17:[function(require,module,exports){ +// base64 decode str -> Uint8Array, to load WA modules +// +'use strict'; + + +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + + +module.exports = function base64decode(str) { + var input = str.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length; + + var out = new Uint8Array((max * 3) >> 2); + + // Collect by 6*4 bits (3 bytes) + + var bits = 0; + var ptr = 0; + + for (var idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + out[ptr++] = (bits >> 16) & 0xFF; + out[ptr++] = (bits >> 8) & 0xFF; + out[ptr++] = bits & 0xFF; + } + + bits = (bits << 6) | BASE64_MAP.indexOf(input.charAt(idx)); + } + + // Dump tail + + var tailbits = (max % 4) * 6; + + if (tailbits === 0) { + out[ptr++] = (bits >> 16) & 0xFF; + out[ptr++] = (bits >> 8) & 0xFF; + out[ptr++] = bits & 0xFF; + } else if (tailbits === 18) { + out[ptr++] = (bits >> 10) & 0xFF; + out[ptr++] = (bits >> 2) & 0xFF; + } else if (tailbits === 12) { + out[ptr++] = (bits >> 4) & 0xFF; + } + + return out; +}; + +},{}],18:[function(require,module,exports){ +// Calculates 16-bit precision HSL lightness from 8-bit rgba buffer +// +'use strict'; + + +module.exports = function hsl_l16_js(img, width, height) { + var size = width * height; + var out = new Uint16Array(size); + var r, g, b, min, max; + for (var i = 0; i < size; i++) { + r = img[4 * i]; + g = img[4 * i + 1]; + b = img[4 * i + 2]; + max = (r >= g && r >= b) ? r : (g >= b && g >= r) ? g : b; + min = (r <= g && r <= b) ? r : (g <= b && g <= r) ? g : b; + out[i] = (max + min) * 257 >> 1; + } + return out; +}; + +},{}],19:[function(require,module,exports){ +'use strict'; + +module.exports = { + name: 'unsharp_mask', + fn: require('./unsharp_mask'), + wasm_fn: require('./unsharp_mask_wasm'), + wasm_src: require('./unsharp_mask_wasm_base64') +}; + +},{"./unsharp_mask":20,"./unsharp_mask_wasm":21,"./unsharp_mask_wasm_base64":22}],20:[function(require,module,exports){ // Unsharp mask filter // // http://stackoverflow.com/a/23322820/1031804 @@ -1261,963 +1246,963 @@ THE SOFTWARE. */ // Image is converted from RGB to HSL, unsharp mask is applied to the // lightness channel and then image is converted back to RGB. // - 'use strict'; - - - var glur_mono16 = require('glur/mono16'); - var hsl_l16 = require('./hsl_l16'); - - - module.exports = function unsharp(img, width, height, amount, radius, threshold) { - var r, g, b; - var h, s, l; - var min, max; - var m1, m2, hShifted; - var diff, iTimes4; - - if (amount === 0 || radius < 0.5) { - return; - } - if (radius > 2.0) { - radius = 2.0; - } - - var lightness = hsl_l16(img, width, height); - - var blured = new Uint16Array(lightness); // copy, because blur modify src - - glur_mono16(blured, width, height, radius); - - var amountFp = (amount / 100 * 0x1000 + 0.5)|0; - var thresholdFp = (threshold * 257)|0; - - var size = width * height; - - /* eslint-disable indent */ - for (var i = 0; i < size; i++) { - diff = 2 * (lightness[i] - blured[i]); - - if (Math.abs(diff) >= thresholdFp) { - iTimes4 = i * 4; - r = img[iTimes4]; - g = img[iTimes4 + 1]; - b = img[iTimes4 + 2]; - - // convert RGB to HSL - // take RGB, 8-bit unsigned integer per each channel - // save HSL, H and L are 16-bit unsigned integers, S is 12-bit unsigned integer - // math is taken from here: http://www.easyrgb.com/index.php?X=MATH&H=18 - // and adopted to be integer (fixed point in fact) for sake of performance - max = (r >= g && r >= b) ? r : (g >= r && g >= b) ? g : b; // min and max are in [0..0xff] - min = (r <= g && r <= b) ? r : (g <= r && g <= b) ? g : b; - l = (max + min) * 257 >> 1; // l is in [0..0xffff] that is caused by multiplication by 257 - - if (min === max) { - h = s = 0; - } else { - s = (l <= 0x7fff) ? - (((max - min) * 0xfff) / (max + min))|0 : - (((max - min) * 0xfff) / (2 * 0xff - max - min))|0; // s is in [0..0xfff] - // h could be less 0, it will be fixed in backward conversion to RGB, |h| <= 0xffff / 6 - h = (r === max) ? (((g - b) * 0xffff) / (6 * (max - min)))|0 - : (g === max) ? 0x5555 + ((((b - r) * 0xffff) / (6 * (max - min)))|0) // 0x5555 == 0xffff / 3 - : 0xaaaa + ((((r - g) * 0xffff) / (6 * (max - min)))|0); // 0xaaaa == 0xffff * 2 / 3 - } - - // add unsharp mask mask to the lightness channel - l += (amountFp * diff + 0x800) >> 12; - if (l > 0xffff) { - l = 0xffff; - } else if (l < 0) { - l = 0; - } - - // convert HSL back to RGB - // for information about math look above - if (s === 0) { - r = g = b = l >> 8; - } else { - m2 = (l <= 0x7fff) ? (l * (0x1000 + s) + 0x800) >> 12 : - l + (((0xffff - l) * s + 0x800) >> 12); - m1 = 2 * l - m2 >> 8; - m2 >>= 8; - // save result to RGB channels - // R channel - hShifted = (h + 0x5555) & 0xffff; // 0x5555 == 0xffff / 3 - r = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 - : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) - : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 - : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); - // G channel - hShifted = h & 0xffff; - g = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 - : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) - : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 - : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); - // B channel - hShifted = (h - 0x5555) & 0xffff; - b = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 - : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) - : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 - : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); - } - - img[iTimes4] = r; - img[iTimes4 + 1] = g; - img[iTimes4 + 2] = b; - } - } - }; - - },{"./hsl_l16":18,"glur/mono16":14}],21:[function(require,module,exports){ - 'use strict'; - - - module.exports = function unsharp(img, width, height, amount, radius, threshold) { - if (amount === 0 || radius < 0.5) { - return; - } - - if (radius > 2.0) { - radius = 2.0; - } - - var pixels = width * height; - - var img_bytes_cnt = pixels * 4; - var hsl_bytes_cnt = pixels * 2; - var blur_bytes_cnt = pixels * 2; - var blur_line_byte_cnt = Math.max(width, height) * 4; // float32 array - var blur_coeffs_byte_cnt = 8 * 4; // float32 array - - var img_offset = 0; - var hsl_offset = img_bytes_cnt; - var blur_offset = hsl_offset + hsl_bytes_cnt; - var blur_tmp_offset = blur_offset + blur_bytes_cnt; - var blur_line_offset = blur_tmp_offset + blur_bytes_cnt; - var blur_coeffs_offset = blur_line_offset + blur_line_byte_cnt; - - var instance = this.__instance( - 'unsharp_mask', - img_bytes_cnt + hsl_bytes_cnt + blur_bytes_cnt * 2 + blur_line_byte_cnt + blur_coeffs_byte_cnt, - { exp: Math.exp } - ); - - // 32-bit copy is much faster in chrome - var img32 = new Uint32Array(img.buffer); - var mem32 = new Uint32Array(this.__memory.buffer); - mem32.set(img32); - - // HSL - var fn = instance.exports.hsl_l16 || instance.exports._hsl_l16; - fn(img_offset, hsl_offset, width, height); - - // BLUR - fn = instance.exports.blurMono16 || instance.exports._blurMono16; - fn(hsl_offset, blur_offset, blur_tmp_offset, - blur_line_offset, blur_coeffs_offset, width, height, radius); - - // UNSHARP - fn = instance.exports.unsharp || instance.exports._unsharp; - fn(img_offset, img_offset, hsl_offset, - blur_offset, width, height, amount, threshold); - - // 32-bit copy is much faster in chrome - img32.set(new Uint32Array(this.__memory.buffer, 0, pixels)); - }; - - },{}],22:[function(require,module,exports){ +'use strict'; + + +var glur_mono16 = require('glur/mono16'); +var hsl_l16 = require('./hsl_l16'); + + +module.exports = function unsharp(img, width, height, amount, radius, threshold) { + var r, g, b; + var h, s, l; + var min, max; + var m1, m2, hShifted; + var diff, iTimes4; + + if (amount === 0 || radius < 0.5) { + return; + } + if (radius > 2.0) { + radius = 2.0; + } + + var lightness = hsl_l16(img, width, height); + + var blured = new Uint16Array(lightness); // copy, because blur modify src + + glur_mono16(blured, width, height, radius); + + var amountFp = (amount / 100 * 0x1000 + 0.5)|0; + var thresholdFp = (threshold * 257)|0; + + var size = width * height; + + /* eslint-disable indent */ + for (var i = 0; i < size; i++) { + diff = 2 * (lightness[i] - blured[i]); + + if (Math.abs(diff) >= thresholdFp) { + iTimes4 = i * 4; + r = img[iTimes4]; + g = img[iTimes4 + 1]; + b = img[iTimes4 + 2]; + + // convert RGB to HSL + // take RGB, 8-bit unsigned integer per each channel + // save HSL, H and L are 16-bit unsigned integers, S is 12-bit unsigned integer + // math is taken from here: http://www.easyrgb.com/index.php?X=MATH&H=18 + // and adopted to be integer (fixed point in fact) for sake of performance + max = (r >= g && r >= b) ? r : (g >= r && g >= b) ? g : b; // min and max are in [0..0xff] + min = (r <= g && r <= b) ? r : (g <= r && g <= b) ? g : b; + l = (max + min) * 257 >> 1; // l is in [0..0xffff] that is caused by multiplication by 257 + + if (min === max) { + h = s = 0; + } else { + s = (l <= 0x7fff) ? + (((max - min) * 0xfff) / (max + min))|0 : + (((max - min) * 0xfff) / (2 * 0xff - max - min))|0; // s is in [0..0xfff] + // h could be less 0, it will be fixed in backward conversion to RGB, |h| <= 0xffff / 6 + h = (r === max) ? (((g - b) * 0xffff) / (6 * (max - min)))|0 + : (g === max) ? 0x5555 + ((((b - r) * 0xffff) / (6 * (max - min)))|0) // 0x5555 == 0xffff / 3 + : 0xaaaa + ((((r - g) * 0xffff) / (6 * (max - min)))|0); // 0xaaaa == 0xffff * 2 / 3 + } + + // add unsharp mask mask to the lightness channel + l += (amountFp * diff + 0x800) >> 12; + if (l > 0xffff) { + l = 0xffff; + } else if (l < 0) { + l = 0; + } + + // convert HSL back to RGB + // for information about math look above + if (s === 0) { + r = g = b = l >> 8; + } else { + m2 = (l <= 0x7fff) ? (l * (0x1000 + s) + 0x800) >> 12 : + l + (((0xffff - l) * s + 0x800) >> 12); + m1 = 2 * l - m2 >> 8; + m2 >>= 8; + // save result to RGB channels + // R channel + hShifted = (h + 0x5555) & 0xffff; // 0x5555 == 0xffff / 3 + r = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 + : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) + : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 + : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); + // G channel + hShifted = h & 0xffff; + g = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 + : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) + : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 + : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); + // B channel + hShifted = (h - 0x5555) & 0xffff; + b = (hShifted >= 0xaaaa) ? m1 // 0xaaaa == 0xffff * 2 / 3 + : (hShifted >= 0x7fff) ? m1 + ((m2 - m1) * 6 * (0xaaaa - hShifted) + 0x8000 >> 16) + : (hShifted >= 0x2aaa) ? m2 // 0x2aaa == 0xffff / 6 + : m1 + ((m2 - m1) * 6 * hShifted + 0x8000 >> 16); + } + + img[iTimes4] = r; + img[iTimes4 + 1] = g; + img[iTimes4 + 2] = b; + } + } +}; + +},{"./hsl_l16":18,"glur/mono16":14}],21:[function(require,module,exports){ +'use strict'; + + +module.exports = function unsharp(img, width, height, amount, radius, threshold) { + if (amount === 0 || radius < 0.5) { + return; + } + + if (radius > 2.0) { + radius = 2.0; + } + + var pixels = width * height; + + var img_bytes_cnt = pixels * 4; + var hsl_bytes_cnt = pixels * 2; + var blur_bytes_cnt = pixels * 2; + var blur_line_byte_cnt = Math.max(width, height) * 4; // float32 array + var blur_coeffs_byte_cnt = 8 * 4; // float32 array + + var img_offset = 0; + var hsl_offset = img_bytes_cnt; + var blur_offset = hsl_offset + hsl_bytes_cnt; + var blur_tmp_offset = blur_offset + blur_bytes_cnt; + var blur_line_offset = blur_tmp_offset + blur_bytes_cnt; + var blur_coeffs_offset = blur_line_offset + blur_line_byte_cnt; + + var instance = this.__instance( + 'unsharp_mask', + img_bytes_cnt + hsl_bytes_cnt + blur_bytes_cnt * 2 + blur_line_byte_cnt + blur_coeffs_byte_cnt, + { exp: Math.exp } + ); + + // 32-bit copy is much faster in chrome + var img32 = new Uint32Array(img.buffer); + var mem32 = new Uint32Array(this.__memory.buffer); + mem32.set(img32); + + // HSL + var fn = instance.exports.hsl_l16 || instance.exports._hsl_l16; + fn(img_offset, hsl_offset, width, height); + + // BLUR + fn = instance.exports.blurMono16 || instance.exports._blurMono16; + fn(hsl_offset, blur_offset, blur_tmp_offset, + blur_line_offset, blur_coeffs_offset, width, height, radius); + + // UNSHARP + fn = instance.exports.unsharp || instance.exports._unsharp; + fn(img_offset, img_offset, hsl_offset, + blur_offset, width, height, amount, threshold); + + // 32-bit copy is much faster in chrome + img32.set(new Uint32Array(this.__memory.buffer, 0, pixels)); +}; + +},{}],22:[function(require,module,exports){ // This is autogenerated file from math.wasm, don't edit. // - 'use strict'; - - /* eslint-disable max-len */ - module.exports = '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'; - - },{}],23:[function(require,module,exports){ +'use strict'; + +/* eslint-disable max-len */ +module.exports = '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'; + +},{}],23:[function(require,module,exports){ // Detect WebAssembly support. // - Check global WebAssembly object // - Try to load simple module (can be disabled via CSP) // - 'use strict'; - - - var wa; - - - module.exports = function hasWebAssembly() { - // use cache if called before; - if (typeof wa !== 'undefined') return wa; - - wa = false; - - if (typeof WebAssembly === 'undefined') return wa; - - // If WebAssenbly is disabled, code can throw on compile - try { - // https://github.com/brion/min-wasm-fail/blob/master/min-wasm-fail.in.js - // Additional check that WA internals are correct - - /* eslint-disable comma-spacing, max-len */ - var bin = new Uint8Array([ 0,97,115,109,1,0,0,0,1,6,1,96,1,127,1,127,3,2,1,0,5,3,1,0,1,7,8,1,4,116,101,115,116,0,0,10,16,1,14,0,32,0,65,1,54,2,0,32,0,40,2,0,11 ]); - var module = new WebAssembly.Module(bin); - var instance = new WebAssembly.Instance(module, {}); - - // test storing to and loading from a non-zero location via a parameter. - // Safari on iOS 11.2.5 returns 0 unexpectedly at non-zero locations - if (instance.exports.test(4) !== 0) wa = true; - - return wa; - } catch (__) {} - - return wa; - }; - - },{}],24:[function(require,module,exports){ - /* - object-assign - (c) Sindre Sorhus - @license MIT - */ - - 'use strict'; - /* eslint-disable no-unused-vars */ - var getOwnPropertySymbols = Object.getOwnPropertySymbols; - var hasOwnProperty = Object.prototype.hasOwnProperty; - var propIsEnumerable = Object.prototype.propertyIsEnumerable; - - function toObject(val) { - if (val === null || val === undefined) { - throw new TypeError('Object.assign cannot be called with null or undefined'); - } - - return Object(val); +'use strict'; + + +var wa; + + +module.exports = function hasWebAssembly() { + // use cache if called before; + if (typeof wa !== 'undefined') return wa; + + wa = false; + + if (typeof WebAssembly === 'undefined') return wa; + + // If WebAssenbly is disabled, code can throw on compile + try { + // https://github.com/brion/min-wasm-fail/blob/master/min-wasm-fail.in.js + // Additional check that WA internals are correct + + /* eslint-disable comma-spacing, max-len */ + var bin = new Uint8Array([ 0,97,115,109,1,0,0,0,1,6,1,96,1,127,1,127,3,2,1,0,5,3,1,0,1,7,8,1,4,116,101,115,116,0,0,10,16,1,14,0,32,0,65,1,54,2,0,32,0,40,2,0,11 ]); + var module = new WebAssembly.Module(bin); + var instance = new WebAssembly.Instance(module, {}); + + // test storing to and loading from a non-zero location via a parameter. + // Safari on iOS 11.2.5 returns 0 unexpectedly at non-zero locations + if (instance.exports.test(4) !== 0) wa = true; + + return wa; + } catch (__) {} + + return wa; +}; + +},{}],24:[function(require,module,exports){ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +'use strict'; +/* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; + +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } + + return Object(val); +} + +function shouldUseNative() { + try { + if (!Object.assign) { + return false; } - - function shouldUseNative() { - try { - if (!Object.assign) { - return false; - } - - // Detect buggy property enumeration order in older V8 versions. - - // https://bugs.chromium.org/p/v8/issues/detail?id=4118 - var test1 = new String('abc'); // eslint-disable-line no-new-wrappers - test1[5] = 'de'; - if (Object.getOwnPropertyNames(test1)[0] === '5') { - return false; - } - - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test2 = {}; - for (var i = 0; i < 10; i++) { - test2['_' + String.fromCharCode(i)] = i; - } - var order2 = Object.getOwnPropertyNames(test2).map(function (n) { - return test2[n]; - }); - if (order2.join('') !== '0123456789') { - return false; - } - - // https://bugs.chromium.org/p/v8/issues/detail?id=3056 - var test3 = {}; - 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { - test3[letter] = letter; - }); - if (Object.keys(Object.assign({}, test3)).join('') !== - 'abcdefghijklmnopqrst') { - return false; - } - - return true; - } catch (err) { - // We don't expect any of the above to throw, but better to be safe. - return false; - } + + // Detect buggy property enumeration order in older V8 versions. + + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; } - - module.exports = shouldUseNative() ? Object.assign : function (target, source) { - var from; - var to = toObject(target); - var symbols; - - for (var s = 1; s < arguments.length; s++) { - from = Object(arguments[s]); - - for (var key in from) { - if (hasOwnProperty.call(from, key)) { - to[key] = from[key]; - } - } - - if (getOwnPropertySymbols) { - symbols = getOwnPropertySymbols(from); - for (var i = 0; i < symbols.length; i++) { - if (propIsEnumerable.call(from, symbols[i])) { - to[symbols[i]] = from[symbols[i]]; - } - } - } - } - - return to; - }; - - },{}],25:[function(require,module,exports){ - var bundleFn = arguments[3]; - var sources = arguments[4]; - var cache = arguments[5]; - - var stringify = JSON.stringify; - - module.exports = function (fn, options) { - var wkey; - var cacheKeys = Object.keys(cache); - - for (var i = 0, l = cacheKeys.length; i < l; i++) { - var key = cacheKeys[i]; - var exp = cache[key].exports; - // Using babel as a transpiler to use esmodule, the export will always - // be an object with the default export as a property of it. To ensure - // the existing api and babel esmodule exports are both supported we - // check for both - if (exp === fn || exp && exp.default === fn) { - wkey = key; - break; - } - } - - if (!wkey) { - wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); - var wcache = {}; - for (var i = 0, l = cacheKeys.length; i < l; i++) { - var key = cacheKeys[i]; - wcache[key] = key; - } - sources[wkey] = [ - 'function(require,module,exports){' + fn + '(self); }', - wcache - ]; - } - var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); - - var scache = {}; scache[wkey] = wkey; - sources[skey] = [ - 'function(require,module,exports){' + - // try to call default if defined to also support babel esmodule exports - 'var f = require(' + stringify(wkey) + ');' + - '(f.default ? f.default : f)(self);' + - '}', - scache - ]; - - var workerSources = {}; - resolveSources(skey); - - function resolveSources(key) { - workerSources[key] = true; - - for (var depPath in sources[key][1]) { - var depKey = sources[key][1][depPath]; - if (!workerSources[depKey]) { - resolveSources(depKey); - } - } - } - - var src = '(' + bundleFn + ')({' - + Object.keys(workerSources).map(function (key) { - return stringify(key) + ':[' - + sources[key][0] - + ',' + stringify(sources[key][1]) + ']' - ; - }).join(',') - + '},{},[' + stringify(skey) + '])' - ; - - var URL = window.URL || window.webkitURL || window.mozURL || window.msURL; - - var blob = new Blob([src], { type: 'text/javascript' }); - if (options && options.bare) { return blob; } - var workerUrl = URL.createObjectURL(blob); - var worker = new Worker(workerUrl); - worker.objectURL = workerUrl; - return worker; - }; - - },{}],"/":[function(require,module,exports){ - 'use strict'; - - function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } - - function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - - function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } - - function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } - - var assign = require('object-assign'); - - var webworkify = require('webworkify'); - - var MathLib = require('./lib/mathlib'); - - var Pool = require('./lib/pool'); - - var utils = require('./lib/utils'); - - var worker = require('./lib/worker'); - - var createStages = require('./lib/stepper'); - - var createRegions = require('./lib/tiler'); // Deduplicate pools & limiters with the same configs -// when user creates multiple pica instances. - - - var singletones = {}; - var NEED_SAFARI_FIX = false; - - try { - if (typeof navigator !== 'undefined' && navigator.userAgent) { - NEED_SAFARI_FIX = navigator.userAgent.indexOf('Safari') >= 0; - } - } catch (e) {} - - var concurrency = 1; - - if (typeof navigator !== 'undefined') { - concurrency = Math.min(navigator.hardwareConcurrency || 1, 4); + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; } - - var DEFAULT_PICA_OPTS = { - tile: 1024, - concurrency: concurrency, - features: ['js', 'wasm', 'ww'], - idle: 2000 - }; - var DEFAULT_RESIZE_OPTS = { - quality: 3, - alpha: false, - unsharpAmount: 0, - unsharpRadius: 0.0, - unsharpThreshold: 0 - }; - var CAN_NEW_IMAGE_DATA; - var CAN_CREATE_IMAGE_BITMAP; - - function workerFabric() { - return { - value: webworkify(worker), - destroy: function destroy() { - this.value.terminate(); - - if (typeof window !== 'undefined') { - var url = window.URL || window.webkitURL || window.mozURL || window.msURL; - - if (url && url.revokeObjectURL && this.value.objectURL) { - url.revokeObjectURL(this.value.objectURL); - } - } - } - }; - } //////////////////////////////////////////////////////////////////////////////// -// API methods - - - function Pica(options) { - if (!(this instanceof Pica)) return new Pica(options); - this.options = assign({}, DEFAULT_PICA_OPTS, options || {}); - var limiter_key = "lk_".concat(this.options.concurrency); // Share limiters to avoid multiple parallel workers when user creates - // multiple pica instances. - - this.__limit = singletones[limiter_key] || utils.limiter(this.options.concurrency); - if (!singletones[limiter_key]) singletones[limiter_key] = this.__limit; // List of supported features, according to options & browser/node.js - - this.features = { - js: false, - // pure JS implementation, can be disabled for testing - wasm: false, - // webassembly implementation for heavy functions - cib: false, - // resize via createImageBitmap (only FF at this moment) - ww: false // webworkers - - }; - this.__workersPool = null; // Store requested features for webworkers - - this.__requested_features = []; - this.__mathlib = null; + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; } - - Pica.prototype.init = function () { - var _this = this; - - if (this.__initPromise) return this.__initPromise; // Test if we can create ImageData without canvas and memory copy - - if (CAN_NEW_IMAGE_DATA !== false && CAN_NEW_IMAGE_DATA !== true) { - CAN_NEW_IMAGE_DATA = false; - - if (typeof ImageData !== 'undefined' && typeof Uint8ClampedArray !== 'undefined') { - try { - /* eslint-disable no-new */ - new ImageData(new Uint8ClampedArray(400), 10, 10); - CAN_NEW_IMAGE_DATA = true; - } catch (__) {} - } - } // ImageBitmap can be effective in 2 places: - // - // 1. Threaded jpeg unpack (basic) - // 2. Built-in resize (blocked due problem in chrome, see issue #89) - // - // For basic use we also need ImageBitmap wo support .close() method, - // see https://developer.mozilla.org/ru/docs/Web/API/ImageBitmap - - - if (CAN_CREATE_IMAGE_BITMAP !== false && CAN_CREATE_IMAGE_BITMAP !== true) { - CAN_CREATE_IMAGE_BITMAP = false; - - if (typeof ImageBitmap !== 'undefined') { - if (ImageBitmap.prototype && ImageBitmap.prototype.close) { - CAN_CREATE_IMAGE_BITMAP = true; - } else { - this.debug('ImageBitmap does not support .close(), disabled'); - } - } - } - - var features = this.options.features.slice(); - - if (features.indexOf('all') >= 0) { - features = ['cib', 'wasm', 'js', 'ww']; + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } + + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } +} + +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; + + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; } - - this.__requested_features = features; - this.__mathlib = new MathLib(features); // Check WebWorker support if requested - - if (features.indexOf('ww') >= 0) { - if (typeof window !== 'undefined' && 'Worker' in window) { - // IE <= 11 don't allow to create webworkers from string. We should check it. - // https://connect.microsoft.com/IE/feedback/details/801810/web-workers-from-blob-urls-in-ie-10-and-11 - try { - var wkr = require('webworkify')(function () {}); - - wkr.terminate(); - this.features.ww = true; // pool uniqueness depends on pool config + webworker config - - var wpool_key = "wp_".concat(JSON.stringify(this.options)); - - if (singletones[wpool_key]) { - this.__workersPool = singletones[wpool_key]; - } else { - this.__workersPool = new Pool(workerFabric, this.options.idle); - singletones[wpool_key] = this.__workersPool; - } - } catch (__) {} + } + + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; } } - - var initMath = this.__mathlib.init().then(function (mathlib) { - // Copy detected features - assign(_this.features, mathlib.features); - }); - - var checkCibResize; - - if (!CAN_CREATE_IMAGE_BITMAP) { - checkCibResize = Promise.resolve(false); - } else { - checkCibResize = utils.cib_support().then(function (status) { - if (_this.features.cib && features.indexOf('cib') < 0) { - _this.debug('createImageBitmap() resize supported, but disabled by config'); - - return; - } - - if (features.indexOf('cib') >= 0) _this.features.cib = status; - }); - } // Init math lib. That's async because can load some - - - this.__initPromise = Promise.all([initMath, checkCibResize]).then(function () { - return _this; - }); - return this.__initPromise; - }; - - Pica.prototype.resize = function (from, to, options) { - var _this2 = this; - - this.debug('Start resize...'); - var opts = assign({}, DEFAULT_RESIZE_OPTS); - - if (!isNaN(options)) { - opts = assign(opts, { - quality: options - }); - } else if (options) { - opts = assign(opts, options); - } - - opts.toWidth = to.width; - opts.toHeight = to.height; - opts.width = from.naturalWidth || from.width; - opts.height = from.naturalHeight || from.height; // Prevent stepper from infinite loop - - if (to.width === 0 || to.height === 0) { - return Promise.reject(new Error("Invalid output size: ".concat(to.width, "x").concat(to.height))); - } - - if (opts.unsharpRadius > 2) opts.unsharpRadius = 2; - var canceled = false; - var cancelToken = null; - - if (opts.cancelToken) { - // Wrap cancelToken to avoid successive resolve & set flag - cancelToken = opts.cancelToken.then(function (data) { - canceled = true; - throw data; - }, function (err) { - canceled = true; - throw err; - }); - } - - var DEST_TILE_BORDER = 3; // Max possible filter window size - - var destTileBorder = Math.ceil(Math.max(DEST_TILE_BORDER, 2.5 * opts.unsharpRadius | 0)); - return this.init().then(function () { - if (canceled) return cancelToken; // if createImageBitmap supports resize, just do it and return - - if (_this2.features.cib) { - var toCtx = to.getContext('2d', { - alpha: Boolean(opts.alpha) - }); - - _this2.debug('Resize via createImageBitmap()'); - - return createImageBitmap(from, { - resizeWidth: opts.toWidth, - resizeHeight: opts.toHeight, - resizeQuality: utils.cib_quality_name(opts.quality) - }).then(function (imageBitmap) { - if (canceled) return cancelToken; // if no unsharp - draw directly to output canvas - - if (!opts.unsharpAmount) { - toCtx.drawImage(imageBitmap, 0, 0); - imageBitmap.close(); - toCtx = null; - - _this2.debug('Finished!'); - - return to; - } - - _this2.debug('Unsharp result'); - - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = opts.toWidth; - tmpCanvas.height = opts.toHeight; - var tmpCtx = tmpCanvas.getContext('2d', { - alpha: Boolean(opts.alpha) - }); - tmpCtx.drawImage(imageBitmap, 0, 0); - imageBitmap.close(); - var iData = tmpCtx.getImageData(0, 0, opts.toWidth, opts.toHeight); - - _this2.__mathlib.unsharp(iData.data, opts.toWidth, opts.toHeight, opts.unsharpAmount, opts.unsharpRadius, opts.unsharpThreshold); - - toCtx.putImageData(iData, 0, 0); - iData = tmpCtx = tmpCanvas = toCtx = null; - - _this2.debug('Finished!'); - - return to; - }); - } // - // No easy way, let's resize manually via arrays - // - // Share cache between calls: - // - // - wasm instance - // - wasm memory object - // - - - var cache = {}; // Call resizer in webworker or locally, depending on config - - var invokeResize = function invokeResize(opts) { - return Promise.resolve().then(function () { - if (!_this2.features.ww) return _this2.__mathlib.resizeAndUnsharp(opts, cache); - return new Promise(function (resolve, reject) { - var w = _this2.__workersPool.acquire(); - - if (cancelToken) cancelToken.catch(function (err) { - return reject(err); - }); - - w.value.onmessage = function (ev) { - w.release(); - if (ev.data.err) reject(ev.data.err);else resolve(ev.data.result); - }; - - w.value.postMessage({ - opts: opts, - features: _this2.__requested_features, - preload: { - wasm_nodule: _this2.__mathlib.__ - } - }, [opts.src.buffer]); - }); - }); - }; - - var tileAndResize = function tileAndResize(from, to, opts) { - var srcCtx; - var srcImageBitmap; - var toCtx; - - var processTile = function processTile(tile) { - return _this2.__limit(function () { - if (canceled) return cancelToken; - var srcImageData; // Extract tile RGBA buffer, depending on input type - - if (utils.isCanvas(from)) { - _this2.debug('Get tile pixel data'); // If input is Canvas - extract region data directly - - - srcImageData = srcCtx.getImageData(tile.x, tile.y, tile.width, tile.height); - } else { - // If input is Image or decoded to ImageBitmap, - // draw region to temporary canvas and extract data from it - // - // Note! Attempt to reuse this canvas causes significant slowdown in chrome - // - _this2.debug('Draw tile imageBitmap/image to temporary canvas'); - - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = tile.width; - tmpCanvas.height = tile.height; - var tmpCtx = tmpCanvas.getContext('2d', { - alpha: Boolean(opts.alpha) - }); - tmpCtx.globalCompositeOperation = 'copy'; - tmpCtx.drawImage(srcImageBitmap || from, tile.x, tile.y, tile.width, tile.height, 0, 0, tile.width, tile.height); - - _this2.debug('Get tile pixel data'); - - srcImageData = tmpCtx.getImageData(0, 0, tile.width, tile.height); - tmpCtx = tmpCanvas = null; - } - - var o = { - src: srcImageData.data, - width: tile.width, - height: tile.height, - toWidth: tile.toWidth, - toHeight: tile.toHeight, - scaleX: tile.scaleX, - scaleY: tile.scaleY, - offsetX: tile.offsetX, - offsetY: tile.offsetY, - quality: opts.quality, - alpha: opts.alpha, - unsharpAmount: opts.unsharpAmount, - unsharpRadius: opts.unsharpRadius, - unsharpThreshold: opts.unsharpThreshold - }; - - _this2.debug('Invoke resize math'); - - return Promise.resolve().then(function () { - return invokeResize(o); - }).then(function (result) { - if (canceled) return cancelToken; - srcImageData = null; - var toImageData; - - _this2.debug('Convert raw rgba tile result to ImageData'); - - if (CAN_NEW_IMAGE_DATA) { - // this branch is for modern browsers - // If `new ImageData()` & Uint8ClampedArray suported - toImageData = new ImageData(new Uint8ClampedArray(result), tile.toWidth, tile.toHeight); - } else { - // fallback for `node-canvas` and old browsers - // (IE11 has ImageData but does not support `new ImageData()`) - toImageData = toCtx.createImageData(tile.toWidth, tile.toHeight); - - if (toImageData.data.set) { - toImageData.data.set(result); - } else { - // IE9 don't have `.set()` - for (var i = toImageData.data.length - 1; i >= 0; i--) { - toImageData.data[i] = result[i]; - } - } - } - - _this2.debug('Draw tile'); - - if (NEED_SAFARI_FIX) { - // Safari draws thin white stripes between tiles without this fix - toCtx.putImageData(toImageData, tile.toX, tile.toY, tile.toInnerX - tile.toX, tile.toInnerY - tile.toY, tile.toInnerWidth + 1e-5, tile.toInnerHeight + 1e-5); - } else { - toCtx.putImageData(toImageData, tile.toX, tile.toY, tile.toInnerX - tile.toX, tile.toInnerY - tile.toY, tile.toInnerWidth, tile.toInnerHeight); - } - - return null; - }); - }); - }; // Need to normalize data source first. It can be canvas or image. - // If image - try to decode in background if possible - - - return Promise.resolve().then(function () { - toCtx = to.getContext('2d', { - alpha: Boolean(opts.alpha) - }); - - if (utils.isCanvas(from)) { - srcCtx = from.getContext('2d', { - alpha: Boolean(opts.alpha) - }); - return null; - } - - if (utils.isImage(from)) { - // try do decode image in background for faster next operations - if (!CAN_CREATE_IMAGE_BITMAP) return null; - - _this2.debug('Decode image via createImageBitmap'); - - return createImageBitmap(from).then(function (imageBitmap) { - srcImageBitmap = imageBitmap; - }); - } - - throw new Error('".from" should be image or canvas'); - }).then(function () { - if (canceled) return cancelToken; - - _this2.debug('Calculate tiles'); // - // Here we are with "normalized" source, - // follow to tiling - // - - - var regions = createRegions({ - width: opts.width, - height: opts.height, - srcTileSize: _this2.options.tile, - toWidth: opts.toWidth, - toHeight: opts.toHeight, - destTileBorder: destTileBorder - }); - var jobs = regions.map(function (tile) { - return processTile(tile); - }); - - function cleanup() { - if (srcImageBitmap) { - srcImageBitmap.close(); - srcImageBitmap = null; - } - } - - _this2.debug('Process tiles'); - - return Promise.all(jobs).then(function () { - _this2.debug('Finished!'); - - cleanup(); - return to; - }, function (err) { - cleanup(); - throw err; - }); - }); - }; - - var processStages = function processStages(stages, from, to, opts) { - if (canceled) return cancelToken; - - var _stages$shift = stages.shift(), - _stages$shift2 = _slicedToArray(_stages$shift, 2), - toWidth = _stages$shift2[0], - toHeight = _stages$shift2[1]; - - var isLastStage = stages.length === 0; - opts = assign({}, opts, { - toWidth: toWidth, - toHeight: toHeight, - // only use user-defined quality for the last stage, - // use simpler (Hamming) filter for the first stages where - // scale factor is large enough (more than 2-3) - quality: isLastStage ? opts.quality : Math.min(1, opts.quality) - }); - var tmpCanvas; - - if (!isLastStage) { - // create temporary canvas - tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = toWidth; - tmpCanvas.height = toHeight; - } - - return tileAndResize(from, isLastStage ? to : tmpCanvas, opts).then(function () { - if (isLastStage) return to; - opts.width = toWidth; - opts.height = toHeight; - return processStages(stages, tmpCanvas, to, opts); - }); - }; - - var stages = createStages(opts.width, opts.height, opts.toWidth, opts.toHeight, _this2.options.tile, destTileBorder); - return processStages(stages, from, to, opts); - }); - }; // RGBA buffer resize + } + } + + return to; +}; + +},{}],25:[function(require,module,exports){ +var bundleFn = arguments[3]; +var sources = arguments[4]; +var cache = arguments[5]; + +var stringify = JSON.stringify; + +module.exports = function (fn, options) { + var wkey; + var cacheKeys = Object.keys(cache); + + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + var exp = cache[key].exports; + // Using babel as a transpiler to use esmodule, the export will always + // be an object with the default export as a property of it. To ensure + // the existing api and babel esmodule exports are both supported we + // check for both + if (exp === fn || exp && exp.default === fn) { + wkey = key; + break; + } + } + + if (!wkey) { + wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + var wcache = {}; + for (var i = 0, l = cacheKeys.length; i < l; i++) { + var key = cacheKeys[i]; + wcache[key] = key; + } + sources[wkey] = [ + 'function(require,module,exports){' + fn + '(self); }', + wcache + ]; + } + var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16); + + var scache = {}; scache[wkey] = wkey; + sources[skey] = [ + 'function(require,module,exports){' + + // try to call default if defined to also support babel esmodule exports + 'var f = require(' + stringify(wkey) + ');' + + '(f.default ? f.default : f)(self);' + + '}', + scache + ]; + + var workerSources = {}; + resolveSources(skey); + + function resolveSources(key) { + workerSources[key] = true; + + for (var depPath in sources[key][1]) { + var depKey = sources[key][1][depPath]; + if (!workerSources[depKey]) { + resolveSources(depKey); + } + } + } + + var src = '(' + bundleFn + ')({' + + Object.keys(workerSources).map(function (key) { + return stringify(key) + ':[' + + sources[key][0] + + ',' + stringify(sources[key][1]) + ']' + ; + }).join(',') + + '},{},[' + stringify(skey) + '])' + ; + + var URL = window.URL || window.webkitURL || window.mozURL || window.msURL; + + var blob = new Blob([src], { type: 'text/javascript' }); + if (options && options.bare) { return blob; } + var workerUrl = URL.createObjectURL(blob); + var worker = new Worker(workerUrl); + worker.objectURL = workerUrl; + return worker; +}; + +},{}],"/":[function(require,module,exports){ +'use strict'; + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +var assign = require('object-assign'); + +var webworkify = require('webworkify'); + +var MathLib = require('./lib/mathlib'); + +var Pool = require('./lib/pool'); + +var utils = require('./lib/utils'); + +var worker = require('./lib/worker'); + +var createStages = require('./lib/stepper'); + +var createRegions = require('./lib/tiler'); // Deduplicate pools & limiters with the same configs +// when user creates multiple pica instances. + + +var singletones = {}; +var NEED_SAFARI_FIX = false; + +try { + if (typeof navigator !== 'undefined' && navigator.userAgent) { + NEED_SAFARI_FIX = navigator.userAgent.indexOf('Safari') >= 0; + } +} catch (e) {} + +var concurrency = 1; + +if (typeof navigator !== 'undefined') { + concurrency = Math.min(navigator.hardwareConcurrency || 1, 4); +} + +var DEFAULT_PICA_OPTS = { + tile: 1024, + concurrency: concurrency, + features: ['js', 'wasm', 'ww'], + idle: 2000 +}; +var DEFAULT_RESIZE_OPTS = { + quality: 3, + alpha: false, + unsharpAmount: 0, + unsharpRadius: 0.0, + unsharpThreshold: 0 +}; +var CAN_NEW_IMAGE_DATA; +var CAN_CREATE_IMAGE_BITMAP; + +function workerFabric() { + return { + value: webworkify(worker), + destroy: function destroy() { + this.value.terminate(); + + if (typeof window !== 'undefined') { + var url = window.URL || window.webkitURL || window.mozURL || window.msURL; + + if (url && url.revokeObjectURL && this.value.objectURL) { + url.revokeObjectURL(this.value.objectURL); + } + } + } + }; +} //////////////////////////////////////////////////////////////////////////////// +// API methods + + +function Pica(options) { + if (!(this instanceof Pica)) return new Pica(options); + this.options = assign({}, DEFAULT_PICA_OPTS, options || {}); + var limiter_key = "lk_".concat(this.options.concurrency); // Share limiters to avoid multiple parallel workers when user creates + // multiple pica instances. + + this.__limit = singletones[limiter_key] || utils.limiter(this.options.concurrency); + if (!singletones[limiter_key]) singletones[limiter_key] = this.__limit; // List of supported features, according to options & browser/node.js + + this.features = { + js: false, + // pure JS implementation, can be disabled for testing + wasm: false, + // webassembly implementation for heavy functions + cib: false, + // resize via createImageBitmap (only FF at this moment) + ww: false // webworkers + + }; + this.__workersPool = null; // Store requested features for webworkers + + this.__requested_features = []; + this.__mathlib = null; +} + +Pica.prototype.init = function () { + var _this = this; + + if (this.__initPromise) return this.__initPromise; // Test if we can create ImageData without canvas and memory copy + + if (CAN_NEW_IMAGE_DATA !== false && CAN_NEW_IMAGE_DATA !== true) { + CAN_NEW_IMAGE_DATA = false; + + if (typeof ImageData !== 'undefined' && typeof Uint8ClampedArray !== 'undefined') { + try { + /* eslint-disable no-new */ + new ImageData(new Uint8ClampedArray(400), 10, 10); + CAN_NEW_IMAGE_DATA = true; + } catch (__) {} + } + } // ImageBitmap can be effective in 2 places: + // + // 1. Threaded jpeg unpack (basic) + // 2. Built-in resize (blocked due problem in chrome, see issue #89) + // + // For basic use we also need ImageBitmap wo support .close() method, + // see https://developer.mozilla.org/ru/docs/Web/API/ImageBitmap + + + if (CAN_CREATE_IMAGE_BITMAP !== false && CAN_CREATE_IMAGE_BITMAP !== true) { + CAN_CREATE_IMAGE_BITMAP = false; + + if (typeof ImageBitmap !== 'undefined') { + if (ImageBitmap.prototype && ImageBitmap.prototype.close) { + CAN_CREATE_IMAGE_BITMAP = true; + } else { + this.debug('ImageBitmap does not support .close(), disabled'); + } + } + } + + var features = this.options.features.slice(); + + if (features.indexOf('all') >= 0) { + features = ['cib', 'wasm', 'js', 'ww']; + } + + this.__requested_features = features; + this.__mathlib = new MathLib(features); // Check WebWorker support if requested + + if (features.indexOf('ww') >= 0) { + if (typeof window !== 'undefined' && 'Worker' in window) { + // IE <= 11 don't allow to create webworkers from string. We should check it. + // https://connect.microsoft.com/IE/feedback/details/801810/web-workers-from-blob-urls-in-ie-10-and-11 + try { + var wkr = require('webworkify')(function () {}); + + wkr.terminate(); + this.features.ww = true; // pool uniqueness depends on pool config + webworker config + + var wpool_key = "wp_".concat(JSON.stringify(this.options)); + + if (singletones[wpool_key]) { + this.__workersPool = singletones[wpool_key]; + } else { + this.__workersPool = new Pool(workerFabric, this.options.idle); + singletones[wpool_key] = this.__workersPool; + } + } catch (__) {} + } + } + + var initMath = this.__mathlib.init().then(function (mathlib) { + // Copy detected features + assign(_this.features, mathlib.features); + }); + + var checkCibResize; + + if (!CAN_CREATE_IMAGE_BITMAP) { + checkCibResize = Promise.resolve(false); + } else { + checkCibResize = utils.cib_support().then(function (status) { + if (_this.features.cib && features.indexOf('cib') < 0) { + _this.debug('createImageBitmap() resize supported, but disabled by config'); + + return; + } + + if (features.indexOf('cib') >= 0) _this.features.cib = status; + }); + } // Init math lib. That's async because can load some + + + this.__initPromise = Promise.all([initMath, checkCibResize]).then(function () { + return _this; + }); + return this.__initPromise; +}; + +Pica.prototype.resize = function (from, to, options) { + var _this2 = this; + + this.debug('Start resize...'); + var opts = assign({}, DEFAULT_RESIZE_OPTS); + + if (!isNaN(options)) { + opts = assign(opts, { + quality: options + }); + } else if (options) { + opts = assign(opts, options); + } + + opts.toWidth = to.width; + opts.toHeight = to.height; + opts.width = from.naturalWidth || from.width; + opts.height = from.naturalHeight || from.height; // Prevent stepper from infinite loop + + if (to.width === 0 || to.height === 0) { + return Promise.reject(new Error("Invalid output size: ".concat(to.width, "x").concat(to.height))); + } + + if (opts.unsharpRadius > 2) opts.unsharpRadius = 2; + var canceled = false; + var cancelToken = null; + + if (opts.cancelToken) { + // Wrap cancelToken to avoid successive resolve & set flag + cancelToken = opts.cancelToken.then(function (data) { + canceled = true; + throw data; + }, function (err) { + canceled = true; + throw err; + }); + } + + var DEST_TILE_BORDER = 3; // Max possible filter window size + + var destTileBorder = Math.ceil(Math.max(DEST_TILE_BORDER, 2.5 * opts.unsharpRadius | 0)); + return this.init().then(function () { + if (canceled) return cancelToken; // if createImageBitmap supports resize, just do it and return + + if (_this2.features.cib) { + var toCtx = to.getContext('2d', { + alpha: Boolean(opts.alpha) + }); + + _this2.debug('Resize via createImageBitmap()'); + + return createImageBitmap(from, { + resizeWidth: opts.toWidth, + resizeHeight: opts.toHeight, + resizeQuality: utils.cib_quality_name(opts.quality) + }).then(function (imageBitmap) { + if (canceled) return cancelToken; // if no unsharp - draw directly to output canvas + + if (!opts.unsharpAmount) { + toCtx.drawImage(imageBitmap, 0, 0); + imageBitmap.close(); + toCtx = null; + + _this2.debug('Finished!'); + + return to; + } + + _this2.debug('Unsharp result'); + + var tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = opts.toWidth; + tmpCanvas.height = opts.toHeight; + var tmpCtx = tmpCanvas.getContext('2d', { + alpha: Boolean(opts.alpha) + }); + tmpCtx.drawImage(imageBitmap, 0, 0); + imageBitmap.close(); + var iData = tmpCtx.getImageData(0, 0, opts.toWidth, opts.toHeight); + + _this2.__mathlib.unsharp_mask(iData.data, opts.toWidth, opts.toHeight, opts.unsharpAmount, opts.unsharpRadius, opts.unsharpThreshold); + + toCtx.putImageData(iData, 0, 0); + iData = tmpCtx = tmpCanvas = toCtx = null; + + _this2.debug('Finished!'); + + return to; + }); + } // + // No easy way, let's resize manually via arrays + // + // Share cache between calls: + // + // - wasm instance + // - wasm memory object + // + + + var cache = {}; // Call resizer in webworker or locally, depending on config + + var invokeResize = function invokeResize(opts) { + return Promise.resolve().then(function () { + if (!_this2.features.ww) return _this2.__mathlib.resizeAndUnsharp(opts, cache); + return new Promise(function (resolve, reject) { + var w = _this2.__workersPool.acquire(); + + if (cancelToken) cancelToken["catch"](function (err) { + return reject(err); + }); + + w.value.onmessage = function (ev) { + w.release(); + if (ev.data.err) reject(ev.data.err);else resolve(ev.data.result); + }; + + w.value.postMessage({ + opts: opts, + features: _this2.__requested_features, + preload: { + wasm_nodule: _this2.__mathlib.__ + } + }, [opts.src.buffer]); + }); + }); + }; + + var tileAndResize = function tileAndResize(from, to, opts) { + var srcCtx; + var srcImageBitmap; + var toCtx; + + var processTile = function processTile(tile) { + return _this2.__limit(function () { + if (canceled) return cancelToken; + var srcImageData; // Extract tile RGBA buffer, depending on input type + + if (utils.isCanvas(from)) { + _this2.debug('Get tile pixel data'); // If input is Canvas - extract region data directly + + + srcImageData = srcCtx.getImageData(tile.x, tile.y, tile.width, tile.height); + } else { + // If input is Image or decoded to ImageBitmap, + // draw region to temporary canvas and extract data from it + // + // Note! Attempt to reuse this canvas causes significant slowdown in chrome + // + _this2.debug('Draw tile imageBitmap/image to temporary canvas'); + + var tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = tile.width; + tmpCanvas.height = tile.height; + var tmpCtx = tmpCanvas.getContext('2d', { + alpha: Boolean(opts.alpha) + }); + tmpCtx.globalCompositeOperation = 'copy'; + tmpCtx.drawImage(srcImageBitmap || from, tile.x, tile.y, tile.width, tile.height, 0, 0, tile.width, tile.height); + + _this2.debug('Get tile pixel data'); + + srcImageData = tmpCtx.getImageData(0, 0, tile.width, tile.height); + tmpCtx = tmpCanvas = null; + } + + var o = { + src: srcImageData.data, + width: tile.width, + height: tile.height, + toWidth: tile.toWidth, + toHeight: tile.toHeight, + scaleX: tile.scaleX, + scaleY: tile.scaleY, + offsetX: tile.offsetX, + offsetY: tile.offsetY, + quality: opts.quality, + alpha: opts.alpha, + unsharpAmount: opts.unsharpAmount, + unsharpRadius: opts.unsharpRadius, + unsharpThreshold: opts.unsharpThreshold + }; + + _this2.debug('Invoke resize math'); + + return Promise.resolve().then(function () { + return invokeResize(o); + }).then(function (result) { + if (canceled) return cancelToken; + srcImageData = null; + var toImageData; + + _this2.debug('Convert raw rgba tile result to ImageData'); + + if (CAN_NEW_IMAGE_DATA) { + // this branch is for modern browsers + // If `new ImageData()` & Uint8ClampedArray suported + toImageData = new ImageData(new Uint8ClampedArray(result), tile.toWidth, tile.toHeight); + } else { + // fallback for `node-canvas` and old browsers + // (IE11 has ImageData but does not support `new ImageData()`) + toImageData = toCtx.createImageData(tile.toWidth, tile.toHeight); + + if (toImageData.data.set) { + toImageData.data.set(result); + } else { + // IE9 don't have `.set()` + for (var i = toImageData.data.length - 1; i >= 0; i--) { + toImageData.data[i] = result[i]; + } + } + } + + _this2.debug('Draw tile'); + + if (NEED_SAFARI_FIX) { + // Safari draws thin white stripes between tiles without this fix + toCtx.putImageData(toImageData, tile.toX, tile.toY, tile.toInnerX - tile.toX, tile.toInnerY - tile.toY, tile.toInnerWidth + 1e-5, tile.toInnerHeight + 1e-5); + } else { + toCtx.putImageData(toImageData, tile.toX, tile.toY, tile.toInnerX - tile.toX, tile.toInnerY - tile.toY, tile.toInnerWidth, tile.toInnerHeight); + } + + return null; + }); + }); + }; // Need to normalize data source first. It can be canvas or image. + // If image - try to decode in background if possible + + + return Promise.resolve().then(function () { + toCtx = to.getContext('2d', { + alpha: Boolean(opts.alpha) + }); + + if (utils.isCanvas(from)) { + srcCtx = from.getContext('2d', { + alpha: Boolean(opts.alpha) + }); + return null; + } + + if (utils.isImage(from)) { + // try do decode image in background for faster next operations + if (!CAN_CREATE_IMAGE_BITMAP) return null; + + _this2.debug('Decode image via createImageBitmap'); + + return createImageBitmap(from).then(function (imageBitmap) { + srcImageBitmap = imageBitmap; + }); + } + + throw new Error('".from" should be image or canvas'); + }).then(function () { + if (canceled) return cancelToken; + + _this2.debug('Calculate tiles'); // + // Here we are with "normalized" source, + // follow to tiling + // + + + var regions = createRegions({ + width: opts.width, + height: opts.height, + srcTileSize: _this2.options.tile, + toWidth: opts.toWidth, + toHeight: opts.toHeight, + destTileBorder: destTileBorder + }); + var jobs = regions.map(function (tile) { + return processTile(tile); + }); + + function cleanup() { + if (srcImageBitmap) { + srcImageBitmap.close(); + srcImageBitmap = null; + } + } + + _this2.debug('Process tiles'); + + return Promise.all(jobs).then(function () { + _this2.debug('Finished!'); + + cleanup(); + return to; + }, function (err) { + cleanup(); + throw err; + }); + }); + }; + + var processStages = function processStages(stages, from, to, opts) { + if (canceled) return cancelToken; + + var _stages$shift = stages.shift(), + _stages$shift2 = _slicedToArray(_stages$shift, 2), + toWidth = _stages$shift2[0], + toHeight = _stages$shift2[1]; + + var isLastStage = stages.length === 0; + opts = assign({}, opts, { + toWidth: toWidth, + toHeight: toHeight, + // only use user-defined quality for the last stage, + // use simpler (Hamming) filter for the first stages where + // scale factor is large enough (more than 2-3) + quality: isLastStage ? opts.quality : Math.min(1, opts.quality) + }); + var tmpCanvas; + + if (!isLastStage) { + // create temporary canvas + tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = toWidth; + tmpCanvas.height = toHeight; + } + + return tileAndResize(from, isLastStage ? to : tmpCanvas, opts).then(function () { + if (isLastStage) return to; + opts.width = toWidth; + opts.height = toHeight; + return processStages(stages, tmpCanvas, to, opts); + }); + }; + + var stages = createStages(opts.width, opts.height, opts.toWidth, opts.toHeight, _this2.options.tile, destTileBorder); + return processStages(stages, from, to, opts); + }); +}; // RGBA buffer resize // - - - Pica.prototype.resizeBuffer = function (options) { - var _this3 = this; - - var opts = assign({}, DEFAULT_RESIZE_OPTS, options); - return this.init().then(function () { - return _this3.__mathlib.resizeAndUnsharp(opts); - }); - }; - - Pica.prototype.toBlob = function (canvas, mimeType, quality) { - mimeType = mimeType || 'image/png'; - return new Promise(function (resolve) { - if (canvas.toBlob) { - canvas.toBlob(function (blob) { - return resolve(blob); - }, mimeType, quality); - return; - } // Fallback for old browsers - - - var asString = atob(canvas.toDataURL(mimeType, quality).split(',')[1]); - var len = asString.length; - var asBuffer = new Uint8Array(len); - - for (var i = 0; i < len; i++) { - asBuffer[i] = asString.charCodeAt(i); - } - - resolve(new Blob([asBuffer], { - type: mimeType - })); - }); - }; - - Pica.prototype.debug = function () {}; - - module.exports = Pica; - - },{"./lib/mathlib":1,"./lib/pool":9,"./lib/stepper":10,"./lib/tiler":11,"./lib/utils":12,"./lib/worker":13,"object-assign":24,"webworkify":25}]},{},[])("/") + + +Pica.prototype.resizeBuffer = function (options) { + var _this3 = this; + + var opts = assign({}, DEFAULT_RESIZE_OPTS, options); + return this.init().then(function () { + return _this3.__mathlib.resizeAndUnsharp(opts); + }); +}; + +Pica.prototype.toBlob = function (canvas, mimeType, quality) { + mimeType = mimeType || 'image/png'; + return new Promise(function (resolve) { + if (canvas.toBlob) { + canvas.toBlob(function (blob) { + return resolve(blob); + }, mimeType, quality); + return; + } // Fallback for old browsers + + + var asString = atob(canvas.toDataURL(mimeType, quality).split(',')[1]); + var len = asString.length; + var asBuffer = new Uint8Array(len); + + for (var i = 0; i < len; i++) { + asBuffer[i] = asString.charCodeAt(i); + } + + resolve(new Blob([asBuffer], { + type: mimeType + })); + }); +}; + +Pica.prototype.debug = function () {}; + +module.exports = Pica; + +},{"./lib/mathlib":1,"./lib/pool":9,"./lib/stepper":10,"./lib/tiler":11,"./lib/utils":12,"./lib/worker":13,"object-assign":24,"webworkify":25}]},{},[])("/") });