diff --git a/codecs/example.webp b/codecs/example.webp new file mode 100644 index 00000000..3bf97b79 Binary files /dev/null and b/codecs/example.webp differ diff --git a/codecs/mozjpeg_enc/example.html b/codecs/mozjpeg_enc/example.html index 8e50ddf7..e03d3ed8 100644 --- a/codecs/mozjpeg_enc/example.html +++ b/codecs/mozjpeg_enc/example.html @@ -27,6 +27,7 @@ get_result_pointer: Module.cwrap('get_result_pointer', 'number', []), get_result_size: Module.cwrap('get_result_size', 'number', []), }; + console.log('Version:', api.version().toString(16)); const image = await loadImage('../example.png'); const p = api.create_buffer(image.width, image.height); Module.HEAP8.set(image.data, p); diff --git a/codecs/webp_dec/README.md b/codecs/webp_dec/README.md new file mode 100644 index 00000000..5b231002 --- /dev/null +++ b/codecs/webp_dec/README.md @@ -0,0 +1,42 @@ +# WebP decoder + +- Source: +- Version: v0.6.1 + +## Example + +See `example.html` + +## API + +### `int version()` + +Returns the version of libwebp as a number. va.b.c is encoded as 0x0a0b0c + +### `uint8_t* create_buffer(int size)` + +Allocates an buffer for the file data. + +### `void destroy_buffer(uint8_t* p)` + +Frees a buffer created with `create_buffer`. + +### `void decode(uint8_t* img_in, int size)` + +Decodes the given webp file into raw RGBA. The result is implicitly stored and can be accessed using the `get_result_*()` functions. + +### `void free_result()` + +Frees the result created by `decode()`. + +### `int get_result_pointer()` + +Returns the pointer to the start of the buffer holding the encoded data. Length is width x height x 4 bytes. + +### `int get_result_width()` + +Returns the width of the image. + +### `int get_result_height()` + +Returns the height of the image. diff --git a/codecs/webp_dec/example.html b/codecs/webp_dec/example.html new file mode 100644 index 00000000..eea1a975 --- /dev/null +++ b/codecs/webp_dec/example.html @@ -0,0 +1,45 @@ + + + diff --git a/codecs/webp_dec/package-lock.json b/codecs/webp_dec/package-lock.json new file mode 100644 index 00000000..39878f31 --- /dev/null +++ b/codecs/webp_dec/package-lock.json @@ -0,0 +1,1147 @@ +{ + "name": "webp_dec", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", + "dev": true + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "dev": true, + "requires": { + "base64-js": "0.0.8", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "config-chain": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", + "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "dev": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "dev": true, + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, + "download": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "dev": true, + "requires": { + "caw": "^2.0.0", + "content-disposition": "^0.5.2", + "decompress": "^4.0.0", + "ext-name": "^5.0.0", + "file-type": "5.2.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^7.0.0", + "make-dir": "^1.0.0", + "p-event": "^1.0.0", + "pify": "^3.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true + }, + "filenamify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.0.0.tgz", + "integrity": "sha1-vRYiYsC26Uv7zc8Zo7uzdk94VpU=", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", + "dev": true, + "requires": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + }, + "make-dir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", + "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mimic-response": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", + "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "napa": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/napa/-/napa-3.0.0.tgz", + "integrity": "sha1-7DqP3gcZC2ny/kNMOVo+aUaEG1Y=", + "dev": true, + "requires": { + "download": "^6.2.2", + "extend": "^3.0.1", + "load-json-file": "^2.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "npm-cache-filename": "^1.0.2", + "npmlog": "^4.1.0", + "rimraf": "^2.6.1", + "tar-pack": "^3.4.0", + "write-json-file": "^2.2.0" + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", + "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=", + "dev": true + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", + "dev": true, + "requires": { + "p-timeout": "^1.1.1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "readable-stream": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", + "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "dev": true, + "requires": { + "commander": "~2.8.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "dev": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, + "strip-outer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz", + "integrity": "sha1-qsC6YNLpDF1PJ1/Yhp/ZotMQ/7g=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "tar-pack": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.1.tgz", + "integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "fstream": "^1.0.10", + "fstream-ignore": "^1.0.5", + "once": "^1.3.3", + "readable-stream": "^2.1.4", + "rimraf": "^2.5.1", + "tar": "^2.2.1", + "uid-number": "^0.0.6" + } + }, + "tar-stream": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", + "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "end-of-stream": "^1.0.0", + "readable-stream": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true + }, + "unbzip2-stream": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", + "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "dev": true, + "requires": { + "buffer": "^3.0.1", + "through": "^2.3.6" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "write-json-file": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz", + "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=", + "dev": true, + "requires": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "pify": "^3.0.0", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.0.0" + }, + "dependencies": { + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/codecs/webp_dec/package.json b/codecs/webp_dec/package.json new file mode 100644 index 00000000..6a5271b2 --- /dev/null +++ b/codecs/webp_dec/package.json @@ -0,0 +1,13 @@ +{ + "name": "webp_dec", + "scripts": { + "install": "napa", + "build": "docker run --rm -v $(pwd):/src trzeci/emscripten emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME=\"webp_dec\"' -I node_modules/libwebp -o ./webp_dec.js webp_dec.c node_modules/libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c" + }, + "napa": { + "libwebp": "webmproject/libwebp#v1.0.0" + }, + "devDependencies": { + "napa": "^3.0.0" + } +} diff --git a/codecs/webp_dec/webp_dec.c b/codecs/webp_dec/webp_dec.c new file mode 100644 index 00000000..eccdb67d --- /dev/null +++ b/codecs/webp_dec/webp_dec.c @@ -0,0 +1,51 @@ +#include "emscripten.h" +#include "src/webp/decode.h" +#include "src/webp/demux.h" +#include + +EMSCRIPTEN_KEEPALIVE +int version() { + return WebPGetDecoderVersion(); +} + +EMSCRIPTEN_KEEPALIVE +uint8_t* create_buffer(int size) { + return malloc(size); +} + +EMSCRIPTEN_KEEPALIVE +void destroy_buffer(uint8_t* p) { + free(p); +} + +int result[3]; +EMSCRIPTEN_KEEPALIVE +void decode(uint8_t* img_in, int size) { + int width, height; + uint8_t* img_out = WebPDecodeRGBA(img_in, size, &width, &height); + result[0] = (int)img_out; + result[1] = width; + result[2] = height; + +} + +EMSCRIPTEN_KEEPALIVE +void free_result() { + WebPFree(result[0]); +} + +EMSCRIPTEN_KEEPALIVE +int get_result_pointer() { + return result[0]; +} + +EMSCRIPTEN_KEEPALIVE +int get_result_width() { + return result[1]; +} + +EMSCRIPTEN_KEEPALIVE +int get_result_height() { + return result[2]; +} + diff --git a/codecs/webp_dec/webp_dec.js b/codecs/webp_dec/webp_dec.js new file mode 100644 index 00000000..cb257285 --- /dev/null +++ b/codecs/webp_dec/webp_dec.js @@ -0,0 +1,17 @@ +var webp_dec = function(webp_dec) { + webp_dec = webp_dec || {}; + +var Module=typeof webp_dec!=="undefined"?webp_dec:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}Module["setWindowTitle"]=(function(title){document.title=title})}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}var JSfuncs={"stackSave":(function(){stackSave()}),"stackRestore":(function(){stackRestore()}),"arrayToC":(function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};function ccall(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;var MIN_TOTAL_MEMORY=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}if(!Module["reallocBuffer"])Module["reallocBuffer"]=(function(size){var ret;try{if(ArrayBuffer.transfer){ret=ArrayBuffer.transfer(buffer,size)}else{var oldHEAP8=HEAP8;ret=new ArrayBuffer(size);var temp=new Int8Array(ret);temp.set(oldHEAP8)}}catch(e){return false}var success=_emscripten_replace_memory(ret);if(!success)return false;return ret});function enlargeMemory(){var PAGE_MULTIPLE=Module["usingWasm"]?WASM_PAGE_SIZE:ASMJS_PAGE_SIZE;var LIMIT=2147483648-PAGE_MULTIPLE;if(HEAP32[DYNAMICTOP_PTR>>2]>LIMIT){return false}var OLD_TOTAL_MEMORY=TOTAL_MEMORY;TOTAL_MEMORY=Math.max(TOTAL_MEMORY,MIN_TOTAL_MEMORY);while(TOTAL_MEMORY>2]){if(TOTAL_MEMORY<=536870912){TOTAL_MEMORY=alignUp(2*TOTAL_MEMORY,PAGE_MULTIPLE)}else{TOTAL_MEMORY=Math.min(alignUp((3*TOTAL_MEMORY+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}var replacement=Module["reallocBuffer"](TOTAL_MEMORY);if(!replacement||replacement.byteLength!=TOTAL_MEMORY){TOTAL_MEMORY=OLD_TOTAL_MEMORY;return false}updateGlobalBuffer(replacement);updateGlobalBufferViews();return true}var byteLength;try{byteLength=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);byteLength(new ArrayBuffer(4))}catch(e){byteLength=(function(buffer){return buffer.byteLength})}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="webp_dec.wast";var wasmBinaryFile="webp_dec.wasm";var asmjsCodeFile="webp_dec.temp.asm.js";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":{"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})},"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;Module["wasmTableSize"]=168;Module["wasmMaxTableSize"]=168;Module.asmGlobalArg={};Module.asmLibraryArg={"abort":abort,"enlargeMemory":enlargeMemory,"getTotalMemory":getTotalMemory,"abortOnCannotGrowMemory":abortOnCannotGrowMemory,"___assert_fail":___assert_fail,"___setErrNo":___setErrNo,"_emscripten_memcpy_big":_emscripten_memcpy_big,"DYNAMICTOP_PTR":DYNAMICTOP_PTR,"STACKTOP":STACKTOP};var asm=Module["asm"](Module.asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=(function(){return Module["asm"]["___errno_location"].apply(null,arguments)});var _create_buffer=Module["_create_buffer"]=(function(){return Module["asm"]["_create_buffer"].apply(null,arguments)});var _decode=Module["_decode"]=(function(){return Module["asm"]["_decode"].apply(null,arguments)});var _destroy_buffer=Module["_destroy_buffer"]=(function(){return Module["asm"]["_destroy_buffer"].apply(null,arguments)});var _emscripten_replace_memory=Module["_emscripten_replace_memory"]=(function(){return Module["asm"]["_emscripten_replace_memory"].apply(null,arguments)});var _free_result=Module["_free_result"]=(function(){return Module["asm"]["_free_result"].apply(null,arguments)});var _get_result_height=Module["_get_result_height"]=(function(){return Module["asm"]["_get_result_height"].apply(null,arguments)});var _get_result_pointer=Module["_get_result_pointer"]=(function(){return Module["asm"]["_get_result_pointer"].apply(null,arguments)});var _get_result_width=Module["_get_result_width"]=(function(){return Module["asm"]["_get_result_width"].apply(null,arguments)});var _version=Module["_version"]=(function(){return Module["asm"]["_version"].apply(null,arguments)});var stackAlloc=Module["stackAlloc"]=(function(){return Module["asm"]["stackAlloc"].apply(null,arguments)});var stackRestore=Module["stackRestore"]=(function(){return Module["asm"]["stackRestore"].apply(null,arguments)});var stackSave=Module["stackSave"]=(function(){return Module["asm"]["stackSave"].apply(null,arguments)});var dynCall_vi=Module["dynCall_vi"]=(function(){return Module["asm"]["dynCall_vi"].apply(null,arguments)});Module["asm"]=asm;Module["cwrap"]=cwrap;Module["then"]=(function(func){if(Module["calledRun"]){func(Module)}else{var old=Module["onRuntimeInitialized"];Module["onRuntimeInitialized"]=(function(){if(old)old();func(Module)})}return Module});function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() + + + + + + return webp_dec; +}; +if (typeof exports === 'object' && typeof module === 'object') + module.exports = webp_dec; +else if (typeof define === 'function' && define['amd']) + define([], function() { return webp_dec; }); +else if (typeof exports === 'object') + exports["webp_dec"] = webp_dec; diff --git a/codecs/webp_dec/webp_dec.wasm b/codecs/webp_dec/webp_dec.wasm new file mode 100644 index 00000000..94a96846 Binary files /dev/null and b/codecs/webp_dec/webp_dec.wasm differ diff --git a/codecs/webp_enc/example.html b/codecs/webp_enc/example.html index 45b9f55c..37dfdf40 100644 --- a/codecs/webp_enc/example.html +++ b/codecs/webp_enc/example.html @@ -27,6 +27,7 @@ get_result_pointer: Module.cwrap('get_result_pointer', 'number', []), get_result_size: Module.cwrap('get_result_size', 'number', []), }; + console.log('Version:', api.version().toString(16)); const image = await loadImage('../example.png'); const p = api.create_buffer(image.width, image.height); Module.HEAP8.set(image.data, p); @@ -38,7 +39,7 @@ api.free_result(resultPointer); api.destroy_buffer(p); - const blob = new Blob([result], {type: 'image/jpeg'}); + const blob = new Blob([result], {type: 'image/webp'}); const blobURL = URL.createObjectURL(blob); const img = document.createElement('img'); img.src = blobURL; diff --git a/codecs/webp_enc/package.json b/codecs/webp_enc/package.json index ff66e9a4..4f66048c 100644 --- a/codecs/webp_enc/package.json +++ b/codecs/webp_enc/package.json @@ -5,7 +5,7 @@ "build": "docker run --rm -v $(pwd):/src trzeci/emscripten emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME=\"webp_enc\"' -I node_modules/libwebp -o ./webp_enc.js webp_enc.c node_modules/libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c" }, "napa": { - "libwebp": "webmproject/libwebp#v0.6.1" + "libwebp": "webmproject/libwebp#v1.0.0" }, "devDependencies": { "napa": "^3.0.0" diff --git a/codecs/webp_enc/webp_enc.js b/codecs/webp_enc/webp_enc.js index af426750..aed44a96 100644 --- a/codecs/webp_enc/webp_enc.js +++ b/codecs/webp_enc/webp_enc.js @@ -1,7 +1,7 @@ var webp_enc = function(webp_enc) { webp_enc = webp_enc || {}; -var Module=typeof webp_enc!=="undefined"?webp_enc:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}Module["setWindowTitle"]=(function(title){document.title=title})}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}var JSfuncs={"stackSave":(function(){stackSave()}),"stackRestore":(function(){stackRestore()}),"arrayToC":(function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};function ccall(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;var MIN_TOTAL_MEMORY=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}if(!Module["reallocBuffer"])Module["reallocBuffer"]=(function(size){var ret;try{if(ArrayBuffer.transfer){ret=ArrayBuffer.transfer(buffer,size)}else{var oldHEAP8=HEAP8;ret=new ArrayBuffer(size);var temp=new Int8Array(ret);temp.set(oldHEAP8)}}catch(e){return false}var success=_emscripten_replace_memory(ret);if(!success)return false;return ret});function enlargeMemory(){var PAGE_MULTIPLE=Module["usingWasm"]?WASM_PAGE_SIZE:ASMJS_PAGE_SIZE;var LIMIT=2147483648-PAGE_MULTIPLE;if(HEAP32[DYNAMICTOP_PTR>>2]>LIMIT){return false}var OLD_TOTAL_MEMORY=TOTAL_MEMORY;TOTAL_MEMORY=Math.max(TOTAL_MEMORY,MIN_TOTAL_MEMORY);while(TOTAL_MEMORY>2]){if(TOTAL_MEMORY<=536870912){TOTAL_MEMORY=alignUp(2*TOTAL_MEMORY,PAGE_MULTIPLE)}else{TOTAL_MEMORY=Math.min(alignUp((3*TOTAL_MEMORY+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}var replacement=Module["reallocBuffer"](TOTAL_MEMORY);if(!replacement||replacement.byteLength!=TOTAL_MEMORY){TOTAL_MEMORY=OLD_TOTAL_MEMORY;return false}updateGlobalBuffer(replacement);updateGlobalBufferViews();return true}var byteLength;try{byteLength=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);byteLength(new ArrayBuffer(4))}catch(e){byteLength=(function(buffer){return buffer.byteLength})}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="webp_enc.wast";var wasmBinaryFile="webp_enc.wasm";var asmjsCodeFile="webp_enc.temp.asm.js";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":{"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})},"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;Module["wasmTableSize"]=118;Module["wasmMaxTableSize"]=118;Module.asmGlobalArg={};Module.asmLibraryArg={"abort":abort,"enlargeMemory":enlargeMemory,"getTotalMemory":getTotalMemory,"abortOnCannotGrowMemory":abortOnCannotGrowMemory,"___assert_fail":___assert_fail,"___setErrNo":___setErrNo,"_emscripten_memcpy_big":_emscripten_memcpy_big,"DYNAMICTOP_PTR":DYNAMICTOP_PTR,"STACKTOP":STACKTOP};var asm=Module["asm"](Module.asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=(function(){return Module["asm"]["___errno_location"].apply(null,arguments)});var _create_buffer=Module["_create_buffer"]=(function(){return Module["asm"]["_create_buffer"].apply(null,arguments)});var _destroy_buffer=Module["_destroy_buffer"]=(function(){return Module["asm"]["_destroy_buffer"].apply(null,arguments)});var _emscripten_replace_memory=Module["_emscripten_replace_memory"]=(function(){return Module["asm"]["_emscripten_replace_memory"].apply(null,arguments)});var _encode=Module["_encode"]=(function(){return Module["asm"]["_encode"].apply(null,arguments)});var _free_result=Module["_free_result"]=(function(){return Module["asm"]["_free_result"].apply(null,arguments)});var _get_result_pointer=Module["_get_result_pointer"]=(function(){return Module["asm"]["_get_result_pointer"].apply(null,arguments)});var _get_result_size=Module["_get_result_size"]=(function(){return Module["asm"]["_get_result_size"].apply(null,arguments)});var _version=Module["_version"]=(function(){return Module["asm"]["_version"].apply(null,arguments)});var stackAlloc=Module["stackAlloc"]=(function(){return Module["asm"]["stackAlloc"].apply(null,arguments)});var stackRestore=Module["stackRestore"]=(function(){return Module["asm"]["stackRestore"].apply(null,arguments)});var stackSave=Module["stackSave"]=(function(){return Module["asm"]["stackSave"].apply(null,arguments)});var dynCall_vi=Module["dynCall_vi"]=(function(){return Module["asm"]["dynCall_vi"].apply(null,arguments)});Module["asm"]=asm;Module["cwrap"]=cwrap;Module["then"]=(function(func){if(Module["calledRun"]){func(Module)}else{var old=Module["onRuntimeInitialized"];Module["onRuntimeInitialized"]=(function(){if(old)old();func(Module)})}return Module});function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() +var Module=typeof webp_enc!=="undefined"?webp_enc:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};if(typeof arguments!="undefined"){Module["arguments"]=arguments}Module["setWindowTitle"]=(function(title){document.title=title})}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}var JSfuncs={"stackSave":(function(){stackSave()}),"stackRestore":(function(){stackRestore()}),"arrayToC":(function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};function ccall(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;var MIN_TOTAL_MEMORY=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}if(!Module["reallocBuffer"])Module["reallocBuffer"]=(function(size){var ret;try{if(ArrayBuffer.transfer){ret=ArrayBuffer.transfer(buffer,size)}else{var oldHEAP8=HEAP8;ret=new ArrayBuffer(size);var temp=new Int8Array(ret);temp.set(oldHEAP8)}}catch(e){return false}var success=_emscripten_replace_memory(ret);if(!success)return false;return ret});function enlargeMemory(){var PAGE_MULTIPLE=Module["usingWasm"]?WASM_PAGE_SIZE:ASMJS_PAGE_SIZE;var LIMIT=2147483648-PAGE_MULTIPLE;if(HEAP32[DYNAMICTOP_PTR>>2]>LIMIT){return false}var OLD_TOTAL_MEMORY=TOTAL_MEMORY;TOTAL_MEMORY=Math.max(TOTAL_MEMORY,MIN_TOTAL_MEMORY);while(TOTAL_MEMORY>2]){if(TOTAL_MEMORY<=536870912){TOTAL_MEMORY=alignUp(2*TOTAL_MEMORY,PAGE_MULTIPLE)}else{TOTAL_MEMORY=Math.min(alignUp((3*TOTAL_MEMORY+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}var replacement=Module["reallocBuffer"](TOTAL_MEMORY);if(!replacement||replacement.byteLength!=TOTAL_MEMORY){TOTAL_MEMORY=OLD_TOTAL_MEMORY;return false}updateGlobalBuffer(replacement);updateGlobalBufferViews();return true}var byteLength;try{byteLength=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);byteLength(new ArrayBuffer(4))}catch(e){byteLength=(function(buffer){return buffer.byteLength})}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="webp_enc.wast";var wasmBinaryFile="webp_enc.wasm";var asmjsCodeFile="webp_enc.temp.asm.js";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":{"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})},"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;Module["wasmTableSize"]=176;Module["wasmMaxTableSize"]=176;Module.asmGlobalArg={};Module.asmLibraryArg={"abort":abort,"enlargeMemory":enlargeMemory,"getTotalMemory":getTotalMemory,"abortOnCannotGrowMemory":abortOnCannotGrowMemory,"___assert_fail":___assert_fail,"___setErrNo":___setErrNo,"_emscripten_memcpy_big":_emscripten_memcpy_big,"DYNAMICTOP_PTR":DYNAMICTOP_PTR,"STACKTOP":STACKTOP};var asm=Module["asm"](Module.asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=(function(){return Module["asm"]["___errno_location"].apply(null,arguments)});var _create_buffer=Module["_create_buffer"]=(function(){return Module["asm"]["_create_buffer"].apply(null,arguments)});var _destroy_buffer=Module["_destroy_buffer"]=(function(){return Module["asm"]["_destroy_buffer"].apply(null,arguments)});var _emscripten_replace_memory=Module["_emscripten_replace_memory"]=(function(){return Module["asm"]["_emscripten_replace_memory"].apply(null,arguments)});var _encode=Module["_encode"]=(function(){return Module["asm"]["_encode"].apply(null,arguments)});var _free_result=Module["_free_result"]=(function(){return Module["asm"]["_free_result"].apply(null,arguments)});var _get_result_pointer=Module["_get_result_pointer"]=(function(){return Module["asm"]["_get_result_pointer"].apply(null,arguments)});var _get_result_size=Module["_get_result_size"]=(function(){return Module["asm"]["_get_result_size"].apply(null,arguments)});var _version=Module["_version"]=(function(){return Module["asm"]["_version"].apply(null,arguments)});var stackAlloc=Module["stackAlloc"]=(function(){return Module["asm"]["stackAlloc"].apply(null,arguments)});var stackRestore=Module["stackRestore"]=(function(){return Module["asm"]["stackRestore"].apply(null,arguments)});var stackSave=Module["stackSave"]=(function(){return Module["asm"]["stackSave"].apply(null,arguments)});var dynCall_vi=Module["dynCall_vi"]=(function(){return Module["asm"]["dynCall_vi"].apply(null,arguments)});Module["asm"]=asm;Module["cwrap"]=cwrap;Module["then"]=(function(func){if(Module["calledRun"]){func(Module)}else{var old=Module["onRuntimeInitialized"];Module["onRuntimeInitialized"]=(function(){if(old)old();func(Module)})}return Module});function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() diff --git a/codecs/webp_enc/webp_enc.wasm b/codecs/webp_enc/webp_enc.wasm index a309988c..4c55c46e 100644 Binary files a/codecs/webp_enc/webp_enc.wasm and b/codecs/webp_enc/webp_enc.wasm differ diff --git a/package.json b/package.json index ce278fc7..35136c19 100644 --- a/package.json +++ b/package.json @@ -8,36 +8,17 @@ "build:codecs": "npm run build:mozjpeg_enc", "start": "webpack serve --host 0.0.0.0 --hot", "build": "webpack -p", - "lint": "eslint src", - "test": "npm run build && npm run test:e2e && npm run test:unit", + "lint": "tslint -c tslint.json -t verbose 'src/**/*.{ts,js}'", + "lintfix": "tslint -c tslint.json -t verbose --fix 'src/**/*.{ts,js}'", + "test": "npm run lint && npm run build && npm run test:e2e && npm run test:unit", "test:e2e": "mocha -R spec test/e2e", "test:unit": "karmatic" }, - "eslintConfig": { - "extends": [ - "standard", - "standard-jsx" - ], - "rules": { - "indent": [ - 2, - 2 - ], - "semi": [ - 2, - "always" - ], - "prefer-const": 1 - }, - "settings": { - "react": { - "pragma": "h" - } + "husky": { + "hooks": { + "pre-commit": "npm run lint" } }, - "eslintIgnore": [ - "build/*" - ], "devDependencies": { "@types/chai": "^4.1.3", "@types/karma": "^1.7.3", @@ -58,18 +39,11 @@ "clean-webpack-plugin": "^0.1.19", "copy-webpack-plugin": "^4.5.1", "css-loader": "^0.28.11", - "eslint": "^4.18.2", - "eslint-config-standard": "^11.0.0", - "eslint-config-standard-jsx": "^5.0.0", - "eslint-plugin-import": "^2.10.0", - "eslint-plugin-node": "^6.0.1", - "eslint-plugin-promise": "^3.7.0", - "eslint-plugin-react": "^7.7.0", - "eslint-plugin-standard": "^3.0.1", "exports-loader": "^0.7.0", "express": "^4.16.3", "file-loader": "^1.1.11", "html-webpack-plugin": "^3.0.6", + "husky": "^1.0.0-rc.9", "if-env": "^1.0.4", "karmatic": "^1.1.7", "loader-utils": "^1.1.0", @@ -85,7 +59,8 @@ "source-map-loader": "^0.2.3", "style-loader": "^0.20.3", "ts-loader": "^4.0.1", - "tslint": "^5.9.1", + "tslint": "^5.10.0", + "tslint-config-airbnb": "^5.9.2", "tslint-config-semistandard": "^7.0.0", "tslint-react": "^3.5.1", "typescript": "^2.7.2", @@ -98,12 +73,12 @@ }, "dependencies": { "classnames": "^2.2.5", + "comlink": "^3.0.3", + "comlink-loader": "^1.0.0", "material-components-web": "^0.32.0", - "material-radial-progress": "git+https://gist.github.com/02134901c77c5309924bfcf8b4435ebe.git", "preact": "^8.2.7", "preact-i18n": "^1.2.0", "preact-material-components": "^1.3.7", - "preact-material-components-drawer": "git+https://gist.github.com/a78fceed440b98e62582e4440b86bfab.git", "preact-router": "^2.6.0" } } diff --git a/src/codecs/encoders.ts b/src/codecs/encoders.ts new file mode 100644 index 00000000..f0158115 --- /dev/null +++ b/src/codecs/encoders.ts @@ -0,0 +1,13 @@ +import * as mozJPEG from './mozjpeg/encoder'; +import * as identity from './identity/encoder'; + +export type EncoderState = identity.EncoderState | mozJPEG.EncoderState; +export type EncoderOptions = identity.EncodeOptions | mozJPEG.EncodeOptions; +export type EncoderType = keyof typeof encoderMap; + +export const encoderMap = { + [identity.type]: identity, + [mozJPEG.type]: mozJPEG, +}; + +export const encoders = Array.from(Object.values(encoderMap)); diff --git a/src/codecs/identity/encoder.ts b/src/codecs/identity/encoder.ts new file mode 100644 index 00000000..84f76d0b --- /dev/null +++ b/src/codecs/identity/encoder.ts @@ -0,0 +1,6 @@ +export interface EncodeOptions {} +export interface EncoderState { type: typeof type; options: EncodeOptions; } + +export const type = 'identity'; +export const label = 'Original image'; +export const defaultOptions: EncodeOptions = {}; diff --git a/src/lib/codec-wrappers/mozjpeg-enc.ts b/src/codecs/mozjpeg/EncoderWorker.ts similarity index 84% rename from src/lib/codec-wrappers/mozjpeg-enc.ts rename to src/codecs/mozjpeg/EncoderWorker.ts index 0971ca73..a4e384a8 100644 --- a/src/lib/codec-wrappers/mozjpeg-enc.ts +++ b/src/codecs/mozjpeg/EncoderWorker.ts @@ -1,7 +1,6 @@ -import {Encoder} from './codec'; - import mozjpeg_enc from '../../../codecs/mozjpeg_enc/mozjpeg_enc'; // Using require() so TypeScript doesn’t complain about this not being a module. +import { EncodeOptions } from './encoder'; const wasmBinaryUrl = require('../../../codecs/mozjpeg_enc/mozjpeg_enc.wasm'); // API exposed by wasm module. Details in the codec’s README. @@ -15,17 +14,18 @@ interface ModuleAPI { get_result_size(): number; } -export class MozJpegEncoder implements Encoder { +export default class MozJpegEncoder { private emscriptenModule: Promise; private api: Promise; + constructor() { - this.emscriptenModule = new Promise(resolve => { + this.emscriptenModule = new Promise((resolve) => { const m = mozjpeg_enc({ // Just to be safe, don’t automatically invoke any wasm functions noInitialRun: false, locateFile(url: string): string { // Redirect the request for the wasm binary to whatever webpack gave us. - if(url.endsWith('.wasm')) { + if (url.endsWith('.wasm')) { return wasmBinaryUrl; } return url; @@ -38,12 +38,14 @@ export class MozJpegEncoder implements Encoder { // TODO(surma@): File a bug with Emscripten on this. delete (m as any).then; resolve(m); - } + }, }); }); this.api = (async () => { - // Not sure why, but TypeScript complains that I am using `emscriptenModule` before it’s getting assigned, which is clearly not true :shrug: Using `any` + // Not sure why, but TypeScript complains that I am using + // `emscriptenModule` before it’s getting assigned, which is clearly not + // true :shrug: Using `any` const m = await (this as any).emscriptenModule; return { version: m.cwrap('version', 'number', []), @@ -57,13 +59,13 @@ export class MozJpegEncoder implements Encoder { })(); } - async encode(data: ImageData): Promise { + async encode(data: ImageData, options: EncodeOptions): Promise { const m = await this.emscriptenModule; const api = await this.api; const p = api.create_buffer(data.width, data.height); m.HEAP8.set(data.data, p); - api.encode(p, data.width, data.height, 2); + api.encode(p, data.width, data.height, options.quality); const resultPointer = api.get_result_pointer(); const resultSize = api.get_result_size(); const resultView = new Uint8Array(m.HEAP8.buffer, resultPointer, resultSize); diff --git a/src/codecs/mozjpeg/encoder.ts b/src/codecs/mozjpeg/encoder.ts new file mode 100644 index 00000000..b61f1ee9 --- /dev/null +++ b/src/codecs/mozjpeg/encoder.ts @@ -0,0 +1,16 @@ +import EncoderWorker from './EncoderWorker'; + +export interface EncodeOptions { quality: number; } +export interface EncoderState { type: typeof type; options: EncodeOptions; } + +export const type = 'mozjpeg'; +export const label = 'MozJPEG'; +export const mimeType = 'image/jpeg'; +export const extension = 'jpg'; +export const defaultOptions: EncodeOptions = { quality: 7 }; + +export async function encode(data: ImageData, options: EncodeOptions) { + // We need to await this because it's been comlinked. + const encoder = await new EncoderWorker(); + return encoder.encode(data, options); +} diff --git a/src/codecs/mozjpeg/options.tsx b/src/codecs/mozjpeg/options.tsx new file mode 100644 index 00000000..3b44a68b --- /dev/null +++ b/src/codecs/mozjpeg/options.tsx @@ -0,0 +1,35 @@ +import { h, Component } from 'preact'; +import { EncodeOptions } from './encoder'; +import { bind } from '../../lib/util'; + +type Props = { + options: EncodeOptions, + onChange(newOptions: EncodeOptions): void +}; + +export default class MozJpegCodecOptions extends Component { + @bind + onChange(event: Event) { + const el = event.currentTarget as HTMLInputElement; + this.props.onChange({ quality: Number(el.value) }); + } + + render({ options }: Props) { + return ( +
+ +
+ ); + } +} diff --git a/src/components/app/custom-els/FileDrop/index.ts b/src/components/app/custom-els/FileDrop/index.ts new file mode 100644 index 00000000..758bb6fc --- /dev/null +++ b/src/components/app/custom-els/FileDrop/index.ts @@ -0,0 +1,117 @@ +import { bind } from '../../../../lib/util'; +import './styles.css'; + +// tslint:disable-next-line:max-line-length +function firstMatchingItem(list: DataTransferItemList, acceptVal: string): DataTransferItem | undefined { + // Split accepts values by ',' then by '/'. Trim everything & lowercase. + const accepts = acceptVal.toLowerCase().split(',').map((accept) => { + return accept.trim().split('/').map(part => part.trim()); + }).filter(acceptParts => acceptParts.length === 2); // Filter invalid values + + return Array.from(list).find((item) => { + if (item.kind !== 'file') return false; + + // 'Parse' the type. + const [typeMain, typeSub] = item.type.toLowerCase().split('/').map(s => s.trim()); + + for (const [acceptMain, acceptSub] of accepts) { + // Look for an exact match, or a partial match if * is accepted, eg image/*. + if (typeMain === acceptMain && (acceptSub === '*' || typeSub === acceptSub)) { + return true; + } + } + return false; + }); +} + +interface FileDropEventInit extends EventInit { + file: File; +} + +export class FileDropEvent extends Event { + private _file: File; + constructor(typeArg: string, eventInitDict: FileDropEventInit) { + super(typeArg, eventInitDict); + this._file = eventInitDict.file; + } + + get file(): File { + return this._file; + } +} + +/* + Example Usage. + + [everything in here is a drop target.] + + + dropElement.addEventListner('dropfile', (event) => console.log(event.detail)) +*/ +export class FileDrop extends HTMLElement { + + private _dragEnterCount = 0; + + constructor() { + super(); + this.addEventListener('dragover', event => event.preventDefault()); + this.addEventListener('drop', this._onDrop); + this.addEventListener('dragenter', this._onDragEnter); + this.addEventListener('dragend', () => this._reset()); + this.addEventListener('dragleave', this._onDragLeave); + } + + get accept() { + return this.getAttribute('accept') || ''; + } + + set accept(val: string) { + this.setAttribute('accept', val); + } + + @bind + private _onDragEnter(event: DragEvent) { + this._dragEnterCount += 1; + if (this._dragEnterCount > 1) return; + + // We don't have data, attempt to get it and if it matches, set the correct state. + const dragDataItem = firstMatchingItem(event.dataTransfer.items, this.accept); + if (dragDataItem) { + this.classList.add('drop-valid'); + } else { + this.classList.add('drop-invalid'); + } + } + + @bind + private _onDragLeave() { + this._dragEnterCount -= 1; + if (this._dragEnterCount === 0) { + this._reset(); + } + } + + @bind + private _onDrop(event: DragEvent) { + event.preventDefault(); + this._reset(); + const dragDataItem = firstMatchingItem(event.dataTransfer.items, this.accept); + if (!dragDataItem) return; + + const file = dragDataItem.getAsFile(); + if (file === null) return; + + this.dispatchEvent(new FileDropEvent('filedrop', { file })); + } + + private _reset() { + this._dragEnterCount = 0; + this.classList.remove('drop-valid'); + this.classList.remove('drop-invalid'); + } +} + +customElements.define('file-drop', FileDrop); diff --git a/src/components/app/custom-els/FileDrop/missing-types.d.ts b/src/components/app/custom-els/FileDrop/missing-types.d.ts new file mode 100644 index 00000000..116ac6f6 --- /dev/null +++ b/src/components/app/custom-els/FileDrop/missing-types.d.ts @@ -0,0 +1,19 @@ +import { FileDropEvent, FileDrop } from '.'; + +declare global { + + interface HTMLElementEventMap { + 'filedrop': FileDropEvent; + } + + namespace JSX { + interface IntrinsicElements { + 'file-drop': FileDropAttributes; + } + + interface FileDropAttributes extends HTMLAttributes { + accept?: string; + onfiledrop?: ((this: FileDrop, ev: FileDropEvent) => any) | null; + } + } +} diff --git a/src/components/app/custom-els/FileDrop/styles.css b/src/components/app/custom-els/FileDrop/styles.css new file mode 100644 index 00000000..ffb6888d --- /dev/null +++ b/src/components/app/custom-els/FileDrop/styles.css @@ -0,0 +1,3 @@ +file-drop { + display: block; +} diff --git a/src/components/app/index.tsx b/src/components/app/index.tsx index 7fade86c..c80c087f 100644 --- a/src/components/app/index.tsx +++ b/src/components/app/index.tsx @@ -2,56 +2,217 @@ import { h, Component } from 'preact'; import { bind, bitmapToImageData } from '../../lib/util'; import * as style from './style.scss'; import Output from '../output'; +import Options from '../options'; +import { FileDropEvent } from './custom-els/FileDrop'; +import './custom-els/FileDrop'; -import {MozJpegEncoder} from '../../lib/codec-wrappers/mozjpeg-enc'; +import * as mozJPEG from '../../codecs/mozjpeg/encoder'; +import * as identity from '../../codecs/identity/encoder'; +import { EncoderState, EncoderType, EncoderOptions, encoderMap } from '../../codecs/encoders'; -type Props = {}; +interface SourceImage { + file: File; + bmp: ImageBitmap; + data: ImageData; +} -type State = { - img?: ImageBitmap -}; +interface EncodedImage { + encoderState: EncoderState; + bmp?: ImageBitmap; + loading: boolean; + /** Counter of the latest bmp currently encoding */ + loadingCounter: number; + /** Counter of the latest bmp encoded */ + loadedCounter: number; +} + +interface Props {} + +interface State { + source?: SourceImage; + images: [EncodedImage, EncodedImage]; + loading: boolean; + error?: string; +} export default class App extends Component { - state: State = {}; + state: State = { + loading: false, + images: [ + { + encoderState: { type: identity.type, options: identity.defaultOptions }, + loadingCounter: 0, + loadedCounter: 0, + loading: false + }, + { + encoderState: { type: mozJPEG.type, options: mozJPEG.defaultOptions }, + loadingCounter: 0, + loadedCounter: 0, + loading: false + } + ] + }; constructor() { super(); // In development, persist application state across hot reloads: if (process.env.NODE_ENV === 'development') { this.setState(window.STATE); - this.componentDidUpdate = () => { + const oldCDU = this.componentDidUpdate; + this.componentDidUpdate = (props, state) => { + if (oldCDU) oldCDU.call(this, props, state); window.STATE = this.state; }; } } - @bind - async onFileChange(event: Event) { - const fileInput = event.target as HTMLInputElement; - if (!fileInput.files || !fileInput.files[0]) return; - // TODO: handle decode error - const bitmap = await createImageBitmap(fileInput.files[0]); - const data = await bitmapToImageData(bitmap); - const encoder = new MozJpegEncoder(); - const compressedData = await encoder.encode(data); - const blob = new Blob([compressedData], {type: 'image/jpeg'}); - const compressedImage = await createImageBitmap(blob); - this.setState({ img: compressedImage }); + onEncoderChange(index: 0 | 1, type: EncoderType, options?: EncoderOptions): void { + const images = this.state.images.slice() as [EncodedImage, EncodedImage]; + const image = images[index]; + + // Some type cheating here. + // encoderMap[type].defaultOptions is always safe. + // options should always be correct for the type, but TypeScript isn't smart enough. + const encoderState: EncoderState = { + type, + options: options ? options : encoderMap[type].defaultOptions + } as EncoderState; + + images[index] = { + ...image, + encoderState, + }; + + this.setState({ images }); } - render({ }: Props, { img }: State) { - return ( -
- {img ? - - : -
-

Select an image

- -
+ onOptionsChange(index: 0 | 1, options: EncoderOptions): void { + this.onEncoderChange(index, this.state.images[index].encoderState.type, options); + } + + componentDidUpdate(prevProps: Props, prevState: State): void { + const { source, images } = this.state; + + for (const [i, image] of images.entries()) { + if (source !== prevState.source || image !== prevState.images[i]) { + this.updateImage(i); + } + } + } + + @bind + async onFileChange(event: Event): Promise { + const fileInput = event.target as HTMLInputElement; + const file = fileInput.files && fileInput.files[0]; + if (!file) return; + await this.updateFile(file); + } + + @bind + async onFileDrop(event: FileDropEvent) { + const { file } = event; + if (!file) return; + await this.updateFile(file); + } + + async updateFile(file: File) { + this.setState({ loading: true }); + try { + const bmp = await createImageBitmap(file); + // compute the corresponding ImageData once since it only changes when the file changes: + const data = await bitmapToImageData(bmp); + this.setState({ + source: { data, bmp, file }, + error: undefined, + loading: false, + }); + } catch (err) { + this.setState({ error: 'IMAGE_INVALID', loading: false }); + } + } + + async updateImage(index: number): Promise { + const { source, images } = this.state; + if (!source) return; + let image = images[index]; + + // Each time we trigger an async encode, the ID changes. + image.loadingCounter = image.loadingCounter + 1; + const loadingCounter = image.loadingCounter; + + image.loading = true; + this.setState({ }); + + const result = await this.updateCompressedImage(source, image.encoderState); + + image = this.state.images[index]; + // If a later encode has landed before this one, return. + if (loadingCounter < image.loadedCounter) return; + image.bmp = result; + image.loading = image.loadingCounter !== loadingCounter; + image.loadedCounter = loadingCounter; + this.setState({ }); + } + + async updateCompressedImage(source: SourceImage, encodeData: EncoderState): Promise { + // Special case for identity + if (encodeData.type === identity.type) return source.bmp; + + try { + const compressedData = await (() => { + switch (encodeData.type) { + case mozJPEG.type: return mozJPEG.encode(source.data, encodeData.options); + default: throw Error(`Unexpected encoder name`); } -
+ })(); + + const blob = new Blob([compressedData], { + type: encoderMap[encodeData.type].mimeType + }); + + const bitmap = await createImageBitmap(blob); + this.setState({ error: '' }); + return bitmap; + } catch (err) { + this.setState({ error: `Encoding error (type=${encodeData.type}): ${err}` }); + throw err; + } + } + + render({ }: Props, { loading, error, images, source }: State) { + const [leftImageBmp, rightImageBmp] = images.map(i => i.bmp); + + loading = loading || images.some(image => image.loading); + + return ( + +
+ {(leftImageBmp && rightImageBmp) ? ( + + ) : ( +
+

Select an image

+ +
+ )} + {images.map((image, index) => ( + + {encoderMap[image.encoderState.type].label} + + ))} + {images.map((image, index) => ( + + ))} + {loading && Loading...} + {error && Error: {error}} +
+
); } } - diff --git a/src/components/app/style.scss b/src/components/app/style.scss index d21e3038..693dea9a 100644 --- a/src/components/app/style.scss +++ b/src/components/app/style.scss @@ -1,3 +1,83 @@ -.app h1 { - color: green; +/* +Note: These styles are temporary. They will be replaced before going live. +*/ + +.app { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: hidden; + contain: strict; + + .leftLabel, + .rightLabel { + position: fixed; + bottom: 0; + padding: 5px 10px; + background: rgba(0,0,0,0.5); + color: #fff; + } + + .leftLabel { left: 0; } + .rightLabel { right: 0; } + + .leftOptions, + .rightOptions { + position: fixed; + bottom: 40px; + } + + .leftOptions { left: 10px; } + .rightOptions { right: 10px; } } + +.welcome { + position: absolute; + display: inline-block; + left: 50%; + top: 50%; + padding: 20px; + transform: translate(-50%, -50%); + + h1 { + font-weight: inherit; + font-size: 150%; + text-align: center; + } + + input { + display: inline-block; + width: 16em; + padding: 5px; + margin: 0 auto; + -webkit-appearance: none; + border: 1px solid #b68c86; + background: #f0d3cf; + box-shadow: inset 0 0 1px #fff; + border-radius: 3px; + cursor: pointer; + } +} + +:global { + file-drop { + overflow: hidden; + touch-action: none; + height:100%; + width:100%; + + &.drop-valid { + transition: opacity 200ms ease-in-out, background-color 200ms; + opacity: 0.5; + background-color:green; + } + + &.drop-invalid { + transition: opacity 200ms ease-in-out, background-color 200ms; + opacity: 0.5; + background-color:red; + } + } +} \ No newline at end of file diff --git a/src/components/options/index.tsx b/src/components/options/index.tsx new file mode 100644 index 00000000..f7e861a1 --- /dev/null +++ b/src/components/options/index.tsx @@ -0,0 +1,63 @@ +import { h, Component } from 'preact'; +import * as style from './style.scss'; +import { bind } from '../../lib/util'; +import MozJpegEncoderOptions from '../../codecs/mozjpeg/options'; + +import { type as mozJPEGType } from '../../codecs/mozjpeg/encoder'; +import { type as identityType } from '../../codecs/identity/encoder'; +import { EncoderState, EncoderType, EncoderOptions, encoders } from '../../codecs/encoders'; + +const encoderOptionsComponentMap = { + [mozJPEGType]: MozJpegEncoderOptions, + [identityType]: undefined +}; + +interface Props { + class?: string; + encoderState: EncoderState; + onTypeChange(newType: EncoderType): void; + onOptionsChange(newOptions: EncoderOptions): void; +} + +interface State {} + +export default class Options extends Component { + typeSelect?: HTMLSelectElement; + + @bind + onTypeChange(event: Event) { + const el = event.currentTarget as HTMLSelectElement; + + // The select element only has values matching encoder types, + // so 'as' is safe here. + const type = el.value as EncoderType; + this.props.onTypeChange(type); + } + + render({ class: className, encoderState, onOptionsChange }: Props) { + const EncoderOptionComponent = encoderOptionsComponentMap[encoderState.type]; + + return ( +
+ + {EncoderOptionComponent && + + } +
+ ); + } +} diff --git a/src/components/options/style.scss b/src/components/options/style.scss new file mode 100644 index 00000000..727aaac6 --- /dev/null +++ b/src/components/options/style.scss @@ -0,0 +1,38 @@ +/* +Note: These styles are temporary. They will be replaced before going live. +*/ + +.options { + width: 180px; + padding: 10px; + background: rgba(50,50,50,0.8); + border: 1px solid #222; + box-shadow: inset 0 0 1px #fff, 0 0 1px #fff; + border-radius: 3px; + color: #eee; + overflow: auto; + z-index: 1; + transition: opacity 300ms ease; + + &:not(:hover) { + opacity: .6; + } + + label { + display: block; + padding: 5px; + font-weight: bold; + + select { + margin-left: 5px; + } + + input { + vertical-align: middle; + } + } + + pre { + font-size: 10px; + } +} diff --git a/src/components/output/custom-els/PinchZoom/index.ts b/src/components/output/custom-els/PinchZoom/index.ts index f9259b19..a29e0caf 100644 --- a/src/components/output/custom-els/PinchZoom/index.ts +++ b/src/components/output/custom-els/PinchZoom/index.ts @@ -24,17 +24,17 @@ interface SetTransformOpts { allowChangeEvent?: boolean; } -function getDistance (a: Point, b?: Point): number { +function getDistance(a: Point, b?: Point): number { if (!b) return 0; return Math.sqrt((b.clientX - a.clientX) ** 2 + (b.clientY - a.clientY) ** 2); } -function getMidpoint (a: Point, b?: Point): Point { +function getMidpoint(a: Point, b?: Point): Point { if (!b) return a; return { clientX: (a.clientX + b.clientX) / 2, - clientY: (a.clientY + b.clientY) / 2 + clientY: (a.clientY + b.clientY) / 2, }; } @@ -42,15 +42,15 @@ function getMidpoint (a: Point, b?: Point): Point { // Given that, better to use something everything supports. let cachedSvg: SVGSVGElement; -function getSVG (): SVGSVGElement { +function getSVG(): SVGSVGElement { return cachedSvg || (cachedSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')); } -function createMatrix (): SVGMatrix { +function createMatrix(): SVGMatrix { return getSVG().createSVGMatrix(); } -function createPoint (): SVGPoint { +function createPoint(): SVGPoint { return getSVG().createSVGPoint(); } @@ -62,7 +62,7 @@ export default class PinchZoom extends HTMLElement { // Current transform. private _transform: SVGMatrix = createMatrix(); - constructor () { + constructor() { super(); // Watch for children changes. @@ -79,42 +79,42 @@ export default class PinchZoom extends HTMLElement { event.preventDefault(); return true; }, - move: previousPointers => { + move: (previousPointers) => { this._onPointerMove(previousPointers, pointerTracker.currentPointers); - } + }, }); this.addEventListener('wheel', event => this._onWheel(event)); } - connectedCallback () { + connectedCallback() { this._stageElChange(); } - get x () { + get x() { return this._transform.e; } - get y () { + get y() { return this._transform.f; } - get scale () { + get scale() { return this._transform.a; } /** * Update the stage with a given scale/x/y. */ - setTransform (opts: SetTransformOpts = {}) { + setTransform(opts: SetTransformOpts = {}) { const { scale = this.scale, - allowChangeEvent = false + allowChangeEvent = false, } = opts; let { x = this.x, - y = this.y + y = this.y, } = opts; // If we don't have an element to position, just set the value as given. @@ -144,7 +144,7 @@ export default class PinchZoom extends HTMLElement { bottomRight.y = positioningElBounds.height + topLeft.y; // Calculate the intended position of _positioningEl. - let matrix = createMatrix() + const matrix = createMatrix() .translate(x, y) .scale(scale) // Undo current transform @@ -174,7 +174,7 @@ export default class PinchZoom extends HTMLElement { /** * Update transform values without checking bounds. This is only called in setTransform. */ - _updateTransform (scale: number, x: number, y: number, allowChangeEvent: boolean) { + _updateTransform(scale: number, x: number, y: number, allowChangeEvent: boolean) { // Return if there's no change if ( scale === this.scale && @@ -202,7 +202,7 @@ export default class PinchZoom extends HTMLElement { * require a single element to be the child of , and * that's the element we pan/scale. */ - private _stageElChange () { + private _stageElChange() { this._positioningEl = undefined; if (this.children.length === 0) { @@ -220,7 +220,7 @@ export default class PinchZoom extends HTMLElement { this.setTransform(); } - private _onWheel (event: WheelEvent) { + private _onWheel(event: WheelEvent) { event.preventDefault(); const thisRect = this.getBoundingClientRect(); @@ -239,11 +239,11 @@ export default class PinchZoom extends HTMLElement { this._applyChange({ scaleDiff, originX: event.clientX - thisRect.left, - originY: event.clientY - thisRect.top + originY: event.clientY - thisRect.top, }); } - private _onPointerMove (previousPointers: Pointer[], currentPointers: Pointer[]) { + private _onPointerMove(previousPointers: Pointer[], currentPointers: Pointer[]) { // Combine next points with previous points const thisRect = this.getBoundingClientRect(); @@ -263,16 +263,16 @@ export default class PinchZoom extends HTMLElement { this._applyChange({ originX, originY, scaleDiff, panX: newMidpoint.clientX - prevMidpoint.clientX, - panY: newMidpoint.clientY - prevMidpoint.clientY + panY: newMidpoint.clientY - prevMidpoint.clientY, }); } /** Transform the view & fire a change event */ - private _applyChange (opts: ApplyChangeOpts = {}) { + private _applyChange(opts: ApplyChangeOpts = {}) { const { panX = 0, panY = 0, originX = 0, originY = 0, - scaleDiff = 1 + scaleDiff = 1, } = opts; const matrix = createMatrix() @@ -290,7 +290,7 @@ export default class PinchZoom extends HTMLElement { scale: matrix.a, x: matrix.e, y: matrix.f, - allowChangeEvent: true + allowChangeEvent: true, }); } } diff --git a/src/components/output/custom-els/TwoUp/index.ts b/src/components/output/custom-els/TwoUp/index.ts index 0299fca4..c5dc080a 100644 --- a/src/components/output/custom-els/TwoUp/index.ts +++ b/src/components/output/custom-els/TwoUp/index.ts @@ -46,9 +46,9 @@ export default class TwoUp extends HTMLElement { move: () => { this._pointerChange( pointerTracker.startPointers[0], - pointerTracker.currentPointers[0] + pointerTracker.currentPointers[0], ); - } + }, }); } diff --git a/src/components/output/custom-els/TwoUp/missing-types.d.ts b/src/components/output/custom-els/TwoUp/missing-types.d.ts index 5f71cb61..ebc916bd 100644 --- a/src/components/output/custom-els/TwoUp/missing-types.d.ts +++ b/src/components/output/custom-els/TwoUp/missing-types.d.ts @@ -11,6 +11,6 @@ interface Window { declare namespace JSX { interface IntrinsicElements { - "two-up": HTMLAttributes + 'two-up': HTMLAttributes; } } diff --git a/src/components/output/index.tsx b/src/components/output/index.tsx index 05af4777..2d83ae87 100644 --- a/src/components/output/index.tsx +++ b/src/components/output/index.tsx @@ -3,16 +3,17 @@ import PinchZoom from './custom-els/PinchZoom'; import './custom-els/PinchZoom'; import './custom-els/TwoUp'; import * as style from './style.scss'; -import { bind } from '../../lib/util'; +import { bind, drawBitmapToCanvas } from '../../lib/util'; import { twoUpHandle } from './custom-els/TwoUp/styles.css'; type Props = { - img: ImageBitmap + leftImg: ImageBitmap, + rightImg: ImageBitmap }; type State = {}; -export default class App extends Component { +export default class Output extends Component { state: State = {}; canvasLeft?: HTMLCanvasElement; canvasRight?: HTMLCanvasElement; @@ -20,26 +21,22 @@ export default class App extends Component { pinchZoomRight?: PinchZoom; retargetedEvents = new WeakSet(); - updateCanvases(img: ImageBitmap) { - for (const [i, canvas] of [this.canvasLeft, this.canvasRight].entries()) { - if (!canvas) throw Error('Missing canvas'); - const ctx = canvas.getContext('2d'); - if (!ctx) throw Error('Expected 2d canvas context'); - if (i === 1) { - // This is temporary, to show the images are different - ctx.filter = 'hue-rotate(180deg)'; - } - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(img, 0, 0); + componentDidMount() { + if (this.canvasLeft) { + drawBitmapToCanvas(this.canvasLeft, this.props.leftImg); + } + if (this.canvasRight) { + drawBitmapToCanvas(this.canvasRight, this.props.rightImg); } } - componentDidMount() { - this.updateCanvases(this.props.img); - } - - componentDidUpdate({ img }: Props) { - if (img !== this.props.img) this.updateCanvases(this.props.img); + componentDidUpdate(prevProps: Props) { + if (prevProps.leftImg !== this.props.leftImg && this.canvasLeft) { + drawBitmapToCanvas(this.canvasLeft, this.props.leftImg); + } + if (prevProps.rightImg !== this.props.rightImg && this.canvasRight) { + drawBitmapToCanvas(this.canvasRight, this.props.rightImg); + } } @bind @@ -78,9 +75,9 @@ export default class App extends Component { this.pinchZoomLeft.dispatchEvent(clonedEvent); } - render({ img }: Props, { }: State) { + render({ leftImg, rightImg }: Props, { }: State) { return ( -
+
{ onWheelCapture={this.onRetargetableEvent} > this.pinchZoomLeft = p as PinchZoom}> - this.canvasLeft = c as HTMLCanvasElement} width={img.width} height={img.height} /> + this.canvasLeft = c as HTMLCanvasElement} width={leftImg.width} height={leftImg.height} /> this.pinchZoomRight = p as PinchZoom}> - this.canvasRight = c as HTMLCanvasElement} width={img.width} height={img.height} /> + this.canvasRight = c as HTMLCanvasElement} width={rightImg.width} height={rightImg.height} /> -

And that's all the app does so far!

); } diff --git a/src/components/output/style.scss b/src/components/output/style.scss index 0f709a65..71a38b55 100644 --- a/src/components/output/style.scss +++ b/src/components/output/style.scss @@ -1,3 +1,29 @@ +/* +Note: These styles are temporary. They will be replaced before going live. +*/ + +%fill { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: hidden; + contain: strict; +} + +.output { + @extend %fill; + + > two-up { + @extend %fill; + + > pinch-zoom { + @extend %fill; + } + } +} + .outputCanvas { image-rendering: pixelated; } diff --git a/src/lib/PointerTracker/index.ts b/src/lib/PointerTracker/index.ts index f0ea26a9..fb77b098 100644 --- a/src/lib/PointerTracker/index.ts +++ b/src/lib/PointerTracker/index.ts @@ -32,9 +32,10 @@ const isPointerEvent = (event: any): event is PointerEvent => const noop = () => {}; -type StartCallback = ((pointer: Pointer, event: TouchEvent | PointerEvent | MouseEvent) => boolean); -type MoveCallback = ((previousPointers: Pointer[], event: TouchEvent | PointerEvent | MouseEvent) => void); -type EndCallback = ((pointer: Pointer, event: TouchEvent | PointerEvent | MouseEvent) => void); +export type InputEvent = TouchEvent | PointerEvent | MouseEvent; +type StartCallback = ((pointer: Pointer, event: InputEvent) => boolean); +type MoveCallback = ((previousPointers: Pointer[], event: InputEvent) => void); +type EndCallback = ((pointer: Pointer, event: InputEvent) => void); interface PointerTrackerCallbacks { /** @@ -95,7 +96,7 @@ export class PointerTracker { const { start = () => true, move = noop, - end = noop + end = noop, } = callbacks; this._startCallback = start; @@ -120,7 +121,7 @@ export class PointerTracker { * @param event Related event * @returns Whether the pointer is being tracked. */ - private _triggerPointerStart (pointer: Pointer, event: PointerEvent | MouseEvent | TouchEvent): boolean { + private _triggerPointerStart (pointer: Pointer, event: InputEvent): boolean { if (!this._startCallback(pointer, event)) return false; this.currentPointers.push(pointer); this.startPointers.push(pointer); @@ -193,7 +194,7 @@ export class PointerTracker { * @param event Related event */ @bind - private _triggerPointerEnd (pointer: Pointer, event: PointerEvent | MouseEvent | TouchEvent): boolean { + private _triggerPointerEnd (pointer: Pointer, event: InputEvent): boolean { const index = this.currentPointers.findIndex(p => p.id === pointer.id); // Not a pointer we're interested in? if (index === -1) return false; diff --git a/src/lib/codec-wrappers/codec.ts b/src/lib/codec-wrappers/codec.ts deleted file mode 100644 index d0e632fb..00000000 --- a/src/lib/codec-wrappers/codec.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface Encoder { - encode(data: ImageData): Promise; -} - -export interface Decoder { - decode(data: ArrayBuffer): Promise; -} diff --git a/src/lib/util.ts b/src/lib/util.ts index 3d0e09b7..a7fa3cd3 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -16,12 +16,12 @@ export function bind(target: any, propertyKey: string, descriptor: PropertyDescr // define an instance property pointing to the bound function. // This effectively "caches" the bound prototype method as an instance property. get() { - let bound = descriptor.value.bind(this); + const bound = descriptor.value.bind(this); Object.defineProperty(this, propertyKey, { - value: bound + value: bound, }); return bound; - } + }, }; } @@ -37,9 +37,16 @@ export async function bitmapToImageData(bitmap: ImageBitmap): Promise // Draw image onto canvas const ctx = canvas.getContext('2d'); if (!ctx) { - throw new Error("Could not create canvas context"); + throw new Error('Could not create canvas context'); } ctx.drawImage(bitmap, 0, 0); return ctx.getImageData(0, 0, bitmap.width, bitmap.height); } +/** Replace the contents of a canvas with the given bitmap */ +export function drawBitmapToCanvas(canvas: HTMLCanvasElement, img: ImageBitmap) { + const ctx = canvas.getContext('2d'); + if (!ctx) throw Error('Canvas not initialized'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(img, 0, 0); +} diff --git a/src/style/index.scss b/src/style/index.scss index c9d5b0cf..8af04066 100644 --- a/src/style/index.scss +++ b/src/style/index.scss @@ -1,3 +1,7 @@ +/* +Note: These styles are temporary. They will be replaced before going live. +*/ + @import './reset.scss'; html, body { @@ -5,6 +9,8 @@ html, body { width: 100%; padding: 0; margin: 0; + font: 14px/1.3 Roboto,'Helvetica Neue',arial,helvetica,sans-serif; overflow: hidden; overscroll-behavior: none; + contain: strict; } diff --git a/src/style/reset.scss b/src/style/reset.scss index c863fb75..2d60b927 100644 --- a/src/style/reset.scss +++ b/src/style/reset.scss @@ -1,3 +1,7 @@ +/* +Note: These styles are temporary. They will be replaced before going live. +*/ + button, a, img, input, select, textarea { -webkit-tap-highlight-color: rgba(0,0,0,0); } diff --git a/tslint.json b/tslint.json index dfe18fd9..a1f7e1f1 100644 --- a/tslint.json +++ b/tslint.json @@ -1,16 +1,19 @@ { "extends": [ - "tslint-config-semistandard", + "tslint-config-airbnb", "tslint-react" ], "rules": { - "quotemark": [true, "single", "jsx-double", "avoid-escape"], - "no-use-before-declare": false, - "no-floating-promises": false, - "space-before-function-paren": [true, false], "jsx-boolean-value": [true, "never"], "jsx-no-multiline-js": false, "jsx-no-bind": true, - "jsx-no-lambda": true + "jsx-no-lambda": true, + "function-name": false, + "variable-name": [true, "check-format", "allow-leading-underscore"] + }, + "linterOptions": { + "exclude": [ + "build" + ] } } diff --git a/webpack.config.js b/webpack.config.js index 7d002571..d1ac99f1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -33,7 +33,8 @@ module.exports = function (_, env) { filename: isProd ? '[name].[chunkhash:5].js' : '[name].js', chunkFilename: '[name].chunk.[chunkhash:5].js', path: path.join(__dirname, 'build'), - publicPath: '/' + publicPath: '/', + globalObject: 'self' }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss', '.css'], @@ -97,6 +98,10 @@ module.exports = function (_, env) { } ] }, + { + test: /\.worker.[tj]sx?$/, + loader: 'comlink-loader' + }, { test: /\.tsx?$/, exclude: nodeModules, @@ -111,16 +116,16 @@ module.exports = function (_, env) { { // All the codec files define a global with the same name as their file name. `exports-loader` attaches those to `module.exports`. test: /\/codecs\/.*\.js$/, - loader: 'exports-loader', + loader: 'exports-loader' }, { test: /\/codecs\/.*\.wasm$/, // This is needed to make webpack NOT process wasm files. // See https://github.com/webpack/webpack/issues/6725 type: 'javascript/auto', - loader: 'file-loader', + loader: 'file-loader' } - ], + ] }, plugins: [ new webpack.IgnorePlugin(/(fs)/, /\/codecs\//),