mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-13 01:07:18 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
173d1ea1e5 | ||
|
|
0e90f805a4 |
39
.babelrc
39
.babelrc
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"@babel/preset-typescript",
|
|
||||||
{
|
|
||||||
"jsxPragma": "h"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@parcel/babel-preset-env",
|
|
||||||
{
|
|
||||||
"loose": true,
|
|
||||||
"bugfixes": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"@babel/plugin-transform-react-jsx",
|
|
||||||
{
|
|
||||||
"loose": true,
|
|
||||||
"pragma": "h",
|
|
||||||
"pragmaFrag": "Fragment"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-decorators",
|
|
||||||
{
|
|
||||||
"legacy": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-class-properties",
|
|
||||||
{
|
|
||||||
"loose": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,4 +4,3 @@ node_modules
|
|||||||
*.scss.d.ts
|
*.scss.d.ts
|
||||||
*.css.d.ts
|
*.css.d.ts
|
||||||
*.o
|
*.o
|
||||||
.parcel-cache
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@parcel/config-default",
|
|
||||||
"transformers": {
|
|
||||||
"*.wasm": ["@parcel/transformer-raw"]
|
|
||||||
},
|
|
||||||
"packagers": {
|
|
||||||
"*.wasm": "@parcel/packager-raw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
.proxyrc.js
15
.proxyrc.js
@@ -1,15 +0,0 @@
|
|||||||
module.exports = function(app) {
|
|
||||||
// `app` is an Express instance
|
|
||||||
app.use(function(req, res, next) {
|
|
||||||
const sh = res.setHeader;
|
|
||||||
res.setHeader = function(key, value) {
|
|
||||||
// remove pointless/incorrect charset from binary responses:
|
|
||||||
if (/^content-type$/i.test(key)) {
|
|
||||||
const m = value && value.match(/^(image\/|application\/wasm); charset=.+$/);
|
|
||||||
if (m) value = m[1];
|
|
||||||
}
|
|
||||||
return sh.call(this, key, value);
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -5,5 +5,7 @@ ENV CXXFLAGS "${CFLAGS} -std=c++17"
|
|||||||
ENV LDFLAGS "${CFLAGS}"
|
ENV LDFLAGS "${CFLAGS}"
|
||||||
# Build and cache standard libraries with these flags
|
# Build and cache standard libraries with these flags
|
||||||
RUN emcc ${CXXFLAGS} --bind -xc++ /dev/null -o /dev/null
|
RUN emcc ${CXXFLAGS} --bind -xc++ /dev/null -o /dev/null
|
||||||
|
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
|
||||||
|
RUN /bin/bash -ic 'nvm install 14.7.0'
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
CMD ["sh", "-c", "emmake make -j`nproc`"]
|
CMD ["sh", "-c", "emmake make -j`nproc`"]
|
||||||
|
|||||||
13
codecs/mozjpeg_enc/.emscripten
Normal file
13
codecs/mozjpeg_enc/.emscripten
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import os
|
||||||
|
emsdk_path = "/emsdk/"
|
||||||
|
#NODE_JS = emsdk_path + '/node/12.18.1_64bit/bin/node'
|
||||||
|
# We need a newer version of Node that supports the most recent iteration of Wasm SIMD
|
||||||
|
# and need to enable that experimental support via flag so that autoconf can successfully
|
||||||
|
# detect SIMD support.
|
||||||
|
NODE_JS=["/root/.nvm/versions/node/v14.7.0/bin/node", "--experimental-wasm-simd"]
|
||||||
|
LLVM_ROOT = emsdk_path + '/upstream/bin'
|
||||||
|
BINARYEN_ROOT = emsdk_path + '/upstream'
|
||||||
|
EMSCRIPTEN_ROOT = emsdk_path + '/upstream/emscripten'
|
||||||
|
TEMP_DIR = emsdk_path + '/tmp'
|
||||||
|
COMPILER_ENGINE = NODE_JS
|
||||||
|
JS_ENGINES = [NODE_JS]
|
||||||
@@ -2,14 +2,24 @@ CODEC_URL := https://github.com/mozilla/mozjpeg/archive/v3.3.1.tar.gz
|
|||||||
CODEC_DIR := node_modules/mozjpeg
|
CODEC_DIR := node_modules/mozjpeg
|
||||||
CODEC_OUT_RELATIVE := .libs/libjpeg.a rdswitch.o
|
CODEC_OUT_RELATIVE := .libs/libjpeg.a rdswitch.o
|
||||||
CODEC_OUT := $(addprefix $(CODEC_DIR)/, $(CODEC_OUT_RELATIVE))
|
CODEC_OUT := $(addprefix $(CODEC_DIR)/, $(CODEC_OUT_RELATIVE))
|
||||||
OUT_JS := mozjpeg_enc.js
|
OUT_JS := mozjpeg_enc_simd.js
|
||||||
OUT_WASM := $(OUT_JS:.js=.wasm)
|
OUT_WASM := $(OUT_JS:.js=.wasm)
|
||||||
|
|
||||||
|
CFLAGS += -msimd128 -msse --em-config /src/.emscripten
|
||||||
|
CXXFLAGS += -msimd128 -msse --em-config /src/.emscripten
|
||||||
|
|
||||||
|
#CFLAGS += --em-config /src/.emscripten
|
||||||
|
#CXXFLAGS += --em-config /src/.emscripten
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(OUT_JS)
|
all: $(OUT_JS)
|
||||||
|
|
||||||
%.js: %.cpp $(CODEC_OUT)
|
%.js: %.cpp $(CODEC_OUT)
|
||||||
|
# We just to disable the overridden NODE_JS binary because
|
||||||
|
# `--closure 1` can’t handle arrays in `.emscripten` it seems.
|
||||||
|
# https://github.com/emscripten-core/emsdk/issues/583
|
||||||
|
export EM_NODE_JS='/root/.nvm/versions/node/v14.7.0/bin/node' && \
|
||||||
$(CXX) \
|
$(CXX) \
|
||||||
-I $(CODEC_DIR) \
|
-I $(CODEC_DIR) \
|
||||||
${CXXFLAGS} \
|
${CXXFLAGS} \
|
||||||
@@ -18,6 +28,7 @@ all: $(OUT_JS)
|
|||||||
--closure 1 \
|
--closure 1 \
|
||||||
-s ALLOW_MEMORY_GROWTH=1 \
|
-s ALLOW_MEMORY_GROWTH=1 \
|
||||||
-s MODULARIZE=1 \
|
-s MODULARIZE=1 \
|
||||||
|
-s EXPORT_ES6=1 \
|
||||||
-s 'EXPORT_NAME="$(basename $(@F))"' \
|
-s 'EXPORT_NAME="$(basename $(@F))"' \
|
||||||
-o $@ \
|
-o $@ \
|
||||||
$+
|
$+
|
||||||
|
|||||||
62
codecs/mozjpeg_enc/bench.d8.js
Normal file
62
codecs/mozjpeg_enc/bench.d8.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import mozjpeg from "./mozjpeg_enc.js";
|
||||||
|
import mozjpegSimd from "./mozjpeg_enc_simd.js";
|
||||||
|
|
||||||
|
const width = 2048;
|
||||||
|
const height = 2048;
|
||||||
|
const size = width * height * 4;
|
||||||
|
const data = new Uint8ClampedArray(size);
|
||||||
|
for(let i = 0; i < size; i++) {
|
||||||
|
data[i] = Math.random() * 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
mozjpeg({
|
||||||
|
onRuntimeInitialized() {
|
||||||
|
const start = performance.now();
|
||||||
|
const result = this.encode(data, width, height, {
|
||||||
|
quality: 75,
|
||||||
|
baseline: false,
|
||||||
|
arithmetic: false,
|
||||||
|
progressive: true,
|
||||||
|
optimize_coding: true,
|
||||||
|
smoothing: 0,
|
||||||
|
color_space: 3,
|
||||||
|
quant_table: 3,
|
||||||
|
trellis_multipass: false,
|
||||||
|
trellis_opt_zero: false,
|
||||||
|
trellis_opt_table: false,
|
||||||
|
trellis_loops: 1,
|
||||||
|
auto_subsample: true,
|
||||||
|
chroma_subsample: 2,
|
||||||
|
separate_chroma_quality: false,
|
||||||
|
chroma_quality: 75,
|
||||||
|
});
|
||||||
|
const end = performance.now();
|
||||||
|
console.log("No SIMD", end - start);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mozjpegSimd({
|
||||||
|
onRuntimeInitialized() {
|
||||||
|
const start = performance.now();
|
||||||
|
const result = this.encode(data, width, height, {
|
||||||
|
quality: 75,
|
||||||
|
baseline: false,
|
||||||
|
arithmetic: false,
|
||||||
|
progressive: true,
|
||||||
|
optimize_coding: true,
|
||||||
|
smoothing: 0,
|
||||||
|
color_space: 3,
|
||||||
|
quant_table: 3,
|
||||||
|
trellis_multipass: false,
|
||||||
|
trellis_opt_zero: false,
|
||||||
|
trellis_opt_table: false,
|
||||||
|
trellis_loops: 1,
|
||||||
|
auto_subsample: true,
|
||||||
|
chroma_subsample: 2,
|
||||||
|
separate_chroma_quality: false,
|
||||||
|
chroma_quality: 75,
|
||||||
|
});
|
||||||
|
const end = performance.now();
|
||||||
|
console.log("SIMD", end - start);
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,26 +1,14 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<script src='mozjpeg_enc.js'></script>
|
<script src='mozjpeg_enc.js'></script>
|
||||||
<script>
|
<script>
|
||||||
const module = mozjpeg_enc();
|
const module = mozjpeg_enc({
|
||||||
|
loadFile() {
|
||||||
async function loadImage(src) {
|
return "./mozjpeg_enc.wasm";
|
||||||
// Load image
|
},
|
||||||
const img = document.createElement('img');
|
async onRuntimeInitialized() {
|
||||||
img.src = src;
|
//console.log('Version:', module.version().toString(16));
|
||||||
await new Promise(resolve => img.onload = resolve);
|
|
||||||
// Make canvas same size as image
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
[canvas.width, canvas.height] = [img.width, img.height];
|
|
||||||
// Draw image onto canvas
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
ctx.drawImage(img, 0, 0);
|
|
||||||
return ctx.getImageData(0, 0, img.width, img.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.onRuntimeInitialized = async _ => {
|
|
||||||
console.log('Version:', module.version().toString(16));
|
|
||||||
const image = await loadImage('../example.png');
|
const image = await loadImage('../example.png');
|
||||||
const result = module.encode(image.data, image.width, image.height, {
|
const result = this.encode(image.data, image.width, image.height, {
|
||||||
quality: 75,
|
quality: 75,
|
||||||
baseline: false,
|
baseline: false,
|
||||||
arithmetic: false,
|
arithmetic: false,
|
||||||
@@ -44,5 +32,21 @@
|
|||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.src = blobURL;
|
img.src = blobURL;
|
||||||
document.body.appendChild(img);
|
document.body.appendChild(img);
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadImage(src) {
|
||||||
|
// Load image
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = src;
|
||||||
|
await new Promise(resolve => img.onload = resolve);
|
||||||
|
// Make canvas same size as image
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
[canvas.width, canvas.height] = [img.width, img.height];
|
||||||
|
// Draw image onto canvas
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
return ctx.getImageData(0, 0, img.width, img.height);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
var mozjpeg_enc = (function() {
|
var mozjpeg_enc = (function() {
|
||||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
var _scriptDir = import.meta.url;
|
||||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
|
||||||
return (
|
return (
|
||||||
function(mozjpeg_enc) {
|
function(mozjpeg_enc) {
|
||||||
mozjpeg_enc = mozjpeg_enc || {};
|
mozjpeg_enc = mozjpeg_enc || {};
|
||||||
@@ -63,10 +63,4 @@ d.run=Cb;if(d.preInit)for("function"==typeof d.preInit&&(d.preInit=[d.preInit]);
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
if (typeof exports === 'object' && typeof module === 'object')
|
export default mozjpeg_enc;
|
||||||
module.exports = mozjpeg_enc;
|
|
||||||
else if (typeof define === 'function' && define['amd'])
|
|
||||||
define([], function() { return mozjpeg_enc; });
|
|
||||||
else if (typeof exports === 'object')
|
|
||||||
exports["mozjpeg_enc"] = mozjpeg_enc;
|
|
||||||
|
|
||||||
Binary file not shown.
3
global.d.ts
vendored
3
global.d.ts
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
declare const __webpack_public_path__: string;
|
||||||
|
declare const PRERENDER: boolean;
|
||||||
|
|
||||||
declare interface NodeModule {
|
declare interface NodeModule {
|
||||||
hot: any;
|
hot: any;
|
||||||
}
|
}
|
||||||
|
|||||||
8774
package-lock.json
generated
8774
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
@@ -4,8 +4,8 @@
|
|||||||
"version": "1.11.4",
|
"version": "1.11.4",
|
||||||
"license": "apache-2.0",
|
"license": "apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "parcel serve src/index.html --no-autoinstall --host 0.0.0.0 --dist-dir build",
|
"start": "webpack-dev-server --host 0.0.0.0 --hot",
|
||||||
"build": "parcel build src/index.html --no-autoinstall --dist-dir build",
|
"build": "webpack -p",
|
||||||
"lint": "tslint -c tslint.json -p tsconfig.json -t verbose",
|
"lint": "tslint -c tslint.json -p tsconfig.json -t verbose",
|
||||||
"lintfix": "tslint -c tslint.json -p tsconfig.json -t verbose --fix 'src/**/*.{ts,tsx,js,jsx}'",
|
"lintfix": "tslint -c tslint.json -p tsconfig.json -t verbose --fix 'src/**/*.{ts,tsx,js,jsx}'",
|
||||||
"sizereport": "sizereport --config"
|
"sizereport": "sizereport --config"
|
||||||
@@ -15,27 +15,7 @@
|
|||||||
"pre-commit": "npm run lint"
|
"pre-commit": "npm run lint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": ">0.5%, not IE 11, not op_mini all",
|
|
||||||
"postcss": {
|
|
||||||
"modules": true,
|
|
||||||
"plugins": {
|
|
||||||
"postcss-modules": {
|
|
||||||
"localsConvention": "camelCaseOnly",
|
|
||||||
"generateScopedName": "[name]__[local]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"//": "See https://github.com/GoogleChromeLabs/pointer-tracker/pull/10",
|
|
||||||
"alias": {
|
|
||||||
"pointer-tracker": "./node_modules/pointer-tracker/dist/PointerTracker.mjs"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
|
||||||
"@babel/plugin-proposal-decorators": "^7.10.5",
|
|
||||||
"@babel/plugin-transform-react-jsx": "^7.10.4",
|
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
|
||||||
"@parcel/babel-preset-env": "^2.0.0-alpha.3",
|
|
||||||
"@parcel/types": "^2.0.0-alpha.3",
|
|
||||||
"@types/node": "10.14.15",
|
"@types/node": "10.14.15",
|
||||||
"@types/pretty-bytes": "5.1.0",
|
"@types/pretty-bytes": "5.1.0",
|
||||||
"@types/webassembly-js-api": "0.0.3",
|
"@types/webassembly-js-api": "0.0.3",
|
||||||
@@ -67,16 +47,13 @@
|
|||||||
"node-sass": "4.13.0",
|
"node-sass": "4.13.0",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
"optimize-css-assets-webpack-plugin": "5.0.1",
|
||||||
"parcel": "^2.0.0-beta.1",
|
|
||||||
"pointer-tracker": "2.0.3",
|
"pointer-tracker": "2.0.3",
|
||||||
"postcss-modules": "^3.2.0",
|
|
||||||
"preact": "8.4.2",
|
"preact": "8.4.2",
|
||||||
"prerender-loader": "1.3.0",
|
"prerender-loader": "1.3.0",
|
||||||
"pretty-bytes": "5.3.0",
|
"pretty-bytes": "5.3.0",
|
||||||
"progress-bar-webpack-plugin": "1.12.1",
|
"progress-bar-webpack-plugin": "1.12.1",
|
||||||
"raw-loader": "3.1.0",
|
"raw-loader": "3.1.0",
|
||||||
"readdirp": "3.1.2",
|
"readdirp": "3.1.2",
|
||||||
"sass": "^1.26.10",
|
|
||||||
"sass-loader": "7.3.1",
|
"sass-loader": "7.3.1",
|
||||||
"script-ext-html-webpack-plugin": "2.1.4",
|
"script-ext-html-webpack-plugin": "2.1.4",
|
||||||
"source-map-loader": "0.2.4",
|
"source-map-loader": "0.2.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { builtinDecode, sniffMimeType, canDecodeImage } from '../lib/util';
|
import { builtinDecode, sniffMimeType, canDecodeImage } from '../lib/util';
|
||||||
import Processor from './processor';
|
import Processor from './processor';
|
||||||
import webpDataUrl from 'url:./tiny.webp';
|
import webpDataUrl from 'url-loader!./tiny.webp';
|
||||||
|
|
||||||
const webPSupported = canDecodeImage(webpDataUrl);
|
const webPSupported = canDecodeImage(webpDataUrl);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
import Range from '../../components/range';
|
import Range from '../../components/range';
|
||||||
|
|
||||||
interface EncodeOptions {
|
interface EncodeOptions {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import { inputFieldValueAsNumber, konami, preventDefault } from '../../lib/util';
|
import { inputFieldValueAsNumber, konami, preventDefault } from '../../lib/util';
|
||||||
import { QuantizeOptions } from './processor-meta';
|
import { QuantizeOptions } from './processor-meta';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
import Expander from '../../components/expander';
|
import Expander from '../../components/expander';
|
||||||
import Select from '../../components/select';
|
import Select from '../../components/select';
|
||||||
import Range from '../../components/range';
|
import Range from '../../components/range';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import { inputFieldChecked, inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
import { inputFieldChecked, inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
||||||
import { EncodeOptions, MozJpegColorSpace } from './encoder-meta';
|
import { EncodeOptions, MozJpegColorSpace } from './encoder-meta';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
import Checkbox from '../../components/checkbox';
|
import Checkbox from '../../components/checkbox';
|
||||||
import Expander from '../../components/expander';
|
import Expander from '../../components/expander';
|
||||||
import Select from '../../components/select';
|
import Select from '../../components/select';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { bind } from '../../lib/initial-util';
|
|||||||
import { inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
import { inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
||||||
import { EncodeOptions } from './encoder-meta';
|
import { EncodeOptions } from './encoder-meta';
|
||||||
import Range from '../../components/range';
|
import Range from '../../components/range';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
options: EncodeOptions;
|
options: EncodeOptions;
|
||||||
|
|||||||
@@ -23,19 +23,6 @@ type ProcessorWorkerApi = import('./processor-worker').ProcessorWorkerApi;
|
|||||||
/** How long the worker should be idle before terminating. */
|
/** How long the worker should be idle before terminating. */
|
||||||
const workerTimeout = 10000;
|
const workerTimeout = 10000;
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorator that manages the (re)starting of the worker and aborting existing jobs. Not all
|
|
||||||
* processing jobs require a worker (e.g. the main thread canvas encodes), use the needsWorker
|
|
||||||
* option to control this.
|
|
||||||
*/
|
|
||||||
function processingJob(options: ProcessingJobOptions = {}) {
|
|
||||||
return (target: Processor, propertyKey: string, descriptor: PropertyDescriptor): void => {
|
|
||||||
const processingFunc = descriptor.value;
|
|
||||||
|
|
||||||
descriptor.value = target.runProcessingJob.bind(target, options, processingFunc);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProcessingJobOptions {
|
interface ProcessingJobOptions {
|
||||||
needsWorker?: boolean;
|
needsWorker?: boolean;
|
||||||
}
|
}
|
||||||
@@ -54,43 +41,52 @@ export default class Processor {
|
|||||||
/** setTimeout ID for killing the worker when idle. */
|
/** setTimeout ID for killing the worker when idle. */
|
||||||
private _workerTimeoutId: number = 0;
|
private _workerTimeoutId: number = 0;
|
||||||
|
|
||||||
/** @private */
|
/**
|
||||||
async runProcessingJob(options: ProcessingJobOptions, processingFunc: any, ...args: any[]) {
|
* Decorator that manages the (re)starting of the worker and aborting existing jobs. Not all
|
||||||
|
* processing jobs require a worker (e.g. the main thread canvas encodes), use the needsWorker
|
||||||
|
* option to control this.
|
||||||
|
*/
|
||||||
|
private static _processingJob(options: ProcessingJobOptions = {}) {
|
||||||
const { needsWorker = false } = options;
|
const { needsWorker = false } = options;
|
||||||
|
|
||||||
this._latestJobId += 1;
|
return (target: Processor, propertyKey: string, descriptor: PropertyDescriptor): void => {
|
||||||
const jobId = this._latestJobId;
|
const processingFunc = descriptor.value;
|
||||||
this.abortCurrent();
|
|
||||||
|
|
||||||
if (needsWorker) self.clearTimeout(this._workerTimeoutId);
|
descriptor.value = async function (this: Processor, ...args: any[]) {
|
||||||
|
this._latestJobId += 1;
|
||||||
|
const jobId = this._latestJobId;
|
||||||
|
this.abortCurrent();
|
||||||
|
|
||||||
if (!this._worker && needsWorker) {
|
if (needsWorker) self.clearTimeout(this._workerTimeoutId);
|
||||||
// worker-loader does magic here.
|
|
||||||
// @ts-ignore - Typescript doesn't know about the 2nd param to new Worker, and the
|
|
||||||
// definition can't be overwritten.
|
|
||||||
this._worker = new Worker(
|
|
||||||
'./processor-worker',
|
|
||||||
{ name: 'processor-worker' },
|
|
||||||
// { name: 'processor-worker', type: 'module' },
|
|
||||||
) as Worker;
|
|
||||||
// Need to do some TypeScript trickery to make the type match.
|
|
||||||
this._workerApi = proxy(this._worker) as any as ProcessorWorkerApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._busy = true;
|
if (!this._worker && needsWorker) {
|
||||||
|
// worker-loader does magic here.
|
||||||
|
// @ts-ignore - Typescript doesn't know about the 2nd param to new Worker, and the
|
||||||
|
// definition can't be overwritten.
|
||||||
|
this._worker = new Worker(
|
||||||
|
'./processor-worker',
|
||||||
|
{ name: 'processor-worker', type: 'module' },
|
||||||
|
) as Worker;
|
||||||
|
// Need to do some TypeScript trickery to make the type match.
|
||||||
|
this._workerApi = proxy(this._worker) as any as ProcessorWorkerApi;
|
||||||
|
}
|
||||||
|
|
||||||
const returnVal = Promise.race([
|
this._busy = true;
|
||||||
processingFunc.call(this, ...args),
|
|
||||||
new Promise((_, reject) => { this._abortRejector = reject; }),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Wait for the operation to settle.
|
const returnVal = Promise.race([
|
||||||
await returnVal.catch(() => {});
|
processingFunc.call(this, ...args),
|
||||||
|
new Promise((_, reject) => { this._abortRejector = reject; }),
|
||||||
|
]);
|
||||||
|
|
||||||
// If no other jobs are happening, cleanup.
|
// Wait for the operation to settle.
|
||||||
if (jobId === this._latestJobId) this._jobCleanup();
|
await returnVal.catch(() => {});
|
||||||
|
|
||||||
return returnVal;
|
// If no other jobs are happening, cleanup.
|
||||||
|
if (jobId === this._latestJobId) this._jobCleanup();
|
||||||
|
|
||||||
|
return returnVal;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _jobCleanup(): void {
|
private _jobCleanup(): void {
|
||||||
@@ -120,33 +116,33 @@ export default class Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Off main thread jobs:
|
// Off main thread jobs:
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
imageQuant(data: ImageData, opts: QuantizeOptions): Promise<ImageData> {
|
imageQuant(data: ImageData, opts: QuantizeOptions): Promise<ImageData> {
|
||||||
return this._workerApi!.quantize(data, opts);
|
return this._workerApi!.quantize(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
rotate(
|
rotate(
|
||||||
data: ImageData, opts: import('./rotate/processor-meta').RotateOptions,
|
data: ImageData, opts: import('./rotate/processor-meta').RotateOptions,
|
||||||
): Promise<ImageData> {
|
): Promise<ImageData> {
|
||||||
return this._workerApi!.rotate(data, opts);
|
return this._workerApi!.rotate(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
workerResize(
|
workerResize(
|
||||||
data: ImageData, opts: import('./resize/processor-meta').WorkerResizeOptions,
|
data: ImageData, opts: import('./resize/processor-meta').WorkerResizeOptions,
|
||||||
): Promise<ImageData> {
|
): Promise<ImageData> {
|
||||||
return this._workerApi!.resize(data, opts);
|
return this._workerApi!.resize(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
mozjpegEncode(
|
mozjpegEncode(
|
||||||
data: ImageData, opts: MozJPEGEncoderOptions,
|
data: ImageData, opts: MozJPEGEncoderOptions,
|
||||||
): Promise<ArrayBuffer> {
|
): Promise<ArrayBuffer> {
|
||||||
return this._workerApi!.mozjpegEncode(data, opts);
|
return this._workerApi!.mozjpegEncode(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
async oxiPngEncode(
|
async oxiPngEncode(
|
||||||
data: ImageData, opts: OxiPNGEncoderOptions,
|
data: ImageData, opts: OxiPNGEncoderOptions,
|
||||||
): Promise<ArrayBuffer> {
|
): Promise<ArrayBuffer> {
|
||||||
@@ -156,12 +152,12 @@ export default class Processor {
|
|||||||
return this._workerApi!.oxiPngEncode(pngBuffer, opts);
|
return this._workerApi!.oxiPngEncode(pngBuffer, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
webpEncode(data: ImageData, opts: WebPEncoderOptions): Promise<ArrayBuffer> {
|
webpEncode(data: ImageData, opts: WebPEncoderOptions): Promise<ArrayBuffer> {
|
||||||
return this._workerApi!.webpEncode(data, opts);
|
return this._workerApi!.webpEncode(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob({ needsWorker: true })
|
@Processor._processingJob({ needsWorker: true })
|
||||||
async webpDecode(blob: Blob): Promise<ImageData> {
|
async webpDecode(blob: Blob): Promise<ImageData> {
|
||||||
const data = await blobToArrayBuffer(blob);
|
const data = await blobToArrayBuffer(blob);
|
||||||
return this._workerApi!.webpDecode(data);
|
return this._workerApi!.webpDecode(data);
|
||||||
@@ -169,42 +165,42 @@ export default class Processor {
|
|||||||
|
|
||||||
// Not-worker jobs:
|
// Not-worker jobs:
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserBmpEncode(data: ImageData): Promise<Blob> {
|
browserBmpEncode(data: ImageData): Promise<Blob> {
|
||||||
return browserBMP.encode(data);
|
return browserBMP.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserPngEncode(data: ImageData): Promise<Blob> {
|
browserPngEncode(data: ImageData): Promise<Blob> {
|
||||||
return browserPNG.encode(data);
|
return browserPNG.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserJpegEncode(data: ImageData, opts: BrowserJPEGOptions): Promise<Blob> {
|
browserJpegEncode(data: ImageData, opts: BrowserJPEGOptions): Promise<Blob> {
|
||||||
return browserJPEG.encode(data, opts);
|
return browserJPEG.encode(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserWebpEncode(data: ImageData, opts: BrowserWebpEncodeOptions): Promise<Blob> {
|
browserWebpEncode(data: ImageData, opts: BrowserWebpEncodeOptions): Promise<Blob> {
|
||||||
return browserWebP.encode(data, opts);
|
return browserWebP.encode(data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserGifEncode(data: ImageData): Promise<Blob> {
|
browserGifEncode(data: ImageData): Promise<Blob> {
|
||||||
return browserGIF.encode(data);
|
return browserGIF.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserTiffEncode(data: ImageData): Promise<Blob> {
|
browserTiffEncode(data: ImageData): Promise<Blob> {
|
||||||
return browserTIFF.encode(data);
|
return browserTIFF.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserJp2Encode(data: ImageData): Promise<Blob> {
|
browserJp2Encode(data: ImageData): Promise<Blob> {
|
||||||
return browserJP2.encode(data);
|
return browserJP2.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@processingJob()
|
@Processor._processingJob()
|
||||||
browserPdfEncode(data: ImageData): Promise<Blob> {
|
browserPdfEncode(data: ImageData): Promise<Blob> {
|
||||||
return browserPDF.encode(data);
|
return browserPDF.encode(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
inputFieldValueAsNumber, inputFieldValue, preventDefault, inputFieldChecked,
|
inputFieldValueAsNumber, inputFieldValue, preventDefault, inputFieldChecked,
|
||||||
} from '../../lib/util';
|
} from '../../lib/util';
|
||||||
import { ResizeOptions, isWorkerOptions } from './processor-meta';
|
import { ResizeOptions, isWorkerOptions } from './processor-meta';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
import Checkbox from '../../components/checkbox';
|
import Checkbox from '../../components/checkbox';
|
||||||
import Expander from '../../components/expander';
|
import Expander from '../../components/expander';
|
||||||
import Select from '../../components/select';
|
import Select from '../../components/select';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import { inputFieldCheckedAsNumber, inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
import { inputFieldCheckedAsNumber, inputFieldValueAsNumber, preventDefault } from '../../lib/util';
|
||||||
import { EncodeOptions, WebPImageHint } from './encoder-meta';
|
import { EncodeOptions, WebPImageHint } from './encoder-meta';
|
||||||
import * as style from '../../components/Options/style.module.scss';
|
import * as style from '../../components/Options/style.scss';
|
||||||
import Checkbox from '../../components/checkbox';
|
import Checkbox from '../../components/checkbox';
|
||||||
import Expander from '../../components/expander';
|
import Expander from '../../components/expander';
|
||||||
import Select from '../../components/select';
|
import Select from '../../components/select';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
import { bind, linkRef, Fileish } from '../../lib/initial-util';
|
import { bind, linkRef, Fileish } from '../../lib/initial-util';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import { FileDropEvent } from 'file-drop-element';
|
import { FileDropEvent } from 'file-drop-element';
|
||||||
import 'file-drop-element';
|
import 'file-drop-element';
|
||||||
import SnackBarElement, { SnackOptions } from '../../lib/SnackBar';
|
import SnackBarElement, { SnackOptions } from '../../lib/SnackBar';
|
||||||
@@ -12,9 +12,11 @@ import '../custom-els/LoadingSpinner';
|
|||||||
const ROUTE_EDITOR = '/editor';
|
const ROUTE_EDITOR = '/editor';
|
||||||
|
|
||||||
const compressPromise = import(
|
const compressPromise = import(
|
||||||
|
/* webpackChunkName: "main-app" */
|
||||||
'../compress');
|
'../compress');
|
||||||
|
|
||||||
const swBridgePromise = import(
|
const swBridgePromise = import(
|
||||||
|
/* webpackChunkName: "sw-bridge" */
|
||||||
'../../lib/sw-bridge');
|
'../../lib/sw-bridge');
|
||||||
|
|
||||||
function back() {
|
function back() {
|
||||||
@@ -45,9 +47,8 @@ export default class App extends Component<Props, State> {
|
|||||||
|
|
||||||
compressPromise.then((module) => {
|
compressPromise.then((module) => {
|
||||||
this.setState({ Compress: module.default });
|
this.setState({ Compress: module.default });
|
||||||
}).catch((e) => {
|
}).catch(() => {
|
||||||
this.showSnack('Failed to load app');
|
this.showSnack('Failed to load app');
|
||||||
throw e;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
swBridgePromise.then(async ({ offliner, getSharedImage }) => {
|
swBridgePromise.then(async ({ offliner, getSharedImage }) => {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
right: 10px;
|
right: 10px;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
border: 2px dashed #fff;
|
border: 2px dashed #fff;
|
||||||
background-color: rgba(88, 116, 88, 0.2);
|
background-color:rgba(88, 116, 88, 0.2);
|
||||||
border-color: rgba(65, 129, 65, 0.5);
|
border-color: rgba(65, 129, 65, 0.5);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import { cleanSet, cleanMerge } from '../../lib/clean-modify';
|
import { cleanSet, cleanMerge } from '../../lib/clean-modify';
|
||||||
import OxiPNGEncoderOptions from '../../codecs/oxipng/options';
|
import OxiPNGEncoderOptions from '../../codecs/oxipng/options';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import PointerTracker, { Pointer } from 'pointer-tracker';
|
import PointerTracker, { Pointer } from 'pointer-tracker';
|
||||||
import * as styles from './styles.module.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
const legacyClipCompatAttr = 'legacy-clip-compat';
|
const legacyClipCompatAttr = 'legacy-clip-compat';
|
||||||
const orientationAttr = 'orientation';
|
const orientationAttr = 'orientation';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
import PinchZoom, { ScaleToOpts } from './custom-els/PinchZoom';
|
import PinchZoom, { ScaleToOpts } from './custom-els/PinchZoom';
|
||||||
import './custom-els/PinchZoom';
|
import './custom-els/PinchZoom';
|
||||||
import './custom-els/TwoUp';
|
import './custom-els/TwoUp';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import { bind, linkRef } from '../../lib/initial-util';
|
import { bind, linkRef } from '../../lib/initial-util';
|
||||||
import { shallowEqual, drawDataToCanvas } from '../../lib/util';
|
import { shallowEqual, drawDataToCanvas } from '../../lib/util';
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
ToggleBackgroundActiveIcon,
|
ToggleBackgroundActiveIcon,
|
||||||
RotateIcon,
|
RotateIcon,
|
||||||
} from '../../lib/icons';
|
} from '../../lib/icons';
|
||||||
import { twoUpHandle } from './custom-els/TwoUp/styles.module.css';
|
import { twoUpHandle } from './custom-els/TwoUp/styles.css';
|
||||||
import { InputProcessorState } from '../../codecs/input-processors';
|
import { InputProcessorState } from '../../codecs/input-processors';
|
||||||
import { cleanSet } from '../../lib/clean-modify';
|
import { cleanSet } from '../../lib/clean-modify';
|
||||||
import { SourceImage } from '../compress';
|
import { SourceImage } from '../compress';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import { UncheckedIcon, CheckedIcon } from '../../lib/icons';
|
import { UncheckedIcon, CheckedIcon } from '../../lib/icons';
|
||||||
|
|
||||||
interface Props extends JSX.HTMLAttributes {}
|
interface Props extends JSX.HTMLAttributes {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as style from './styles.module.css';
|
import * as style from './styles.css';
|
||||||
import { transitionHeight } from '../../../../lib/util';
|
import { transitionHeight } from '../../../../lib/util';
|
||||||
|
|
||||||
interface CloseAllOptions {
|
interface CloseAllOptions {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
|
|
||||||
import { bind, Fileish } from '../../lib/initial-util';
|
import { bind, Fileish } from '../../lib/initial-util';
|
||||||
import { blobToImg, drawableToImageData, blobToText } from '../../lib/util';
|
import { blobToImg, drawableToImageData, blobToText } from '../../lib/util';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import Output from '../Output';
|
import Output from '../Output';
|
||||||
import Options from '../Options';
|
import Options from '../Options';
|
||||||
import ResultCache from './result-cache';
|
import ResultCache from './result-cache';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as styles from './styles.module.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple spinner. This custom element has no JS API. Just put it in the document, and it'll
|
* A simple spinner. This custom element has no JS API. Just put it in the document, and it'll
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component, ComponentChild, ComponentChildren } from 'preact';
|
import { h, Component, ComponentChild, ComponentChildren } from 'preact';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import { transitionHeight } from '../../lib/util';
|
import { transitionHeight } from '../../lib/util';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ import { h, Component } from 'preact';
|
|||||||
import { bind, linkRef, Fileish } from '../../lib/initial-util';
|
import { bind, linkRef, Fileish } from '../../lib/initial-util';
|
||||||
import '../custom-els/LoadingSpinner';
|
import '../custom-els/LoadingSpinner';
|
||||||
|
|
||||||
import logo from 'url:./imgs/logo.svg';
|
import logo from './imgs/logo.svg';
|
||||||
import largePhoto from 'url:./imgs/demos/demo-large-photo.jpg';
|
import largePhoto from './imgs/demos/demo-large-photo.jpg';
|
||||||
import artwork from 'url:./imgs/demos/demo-artwork.jpg';
|
import artwork from './imgs/demos/demo-artwork.jpg';
|
||||||
import deviceScreen from 'url:./imgs/demos/demo-device-screen.png';
|
import deviceScreen from './imgs/demos/demo-device-screen.png';
|
||||||
import largePhotoIcon from 'url:./imgs/demos/icon-demo-large-photo.jpg';
|
import largePhotoIcon from './imgs/demos/icon-demo-large-photo.jpg';
|
||||||
import artworkIcon from 'url:./imgs/demos/icon-demo-artwork.jpg';
|
import artworkIcon from './imgs/demos/icon-demo-artwork.jpg';
|
||||||
import deviceScreenIcon from 'url:./imgs/demos/icon-demo-device-screen.jpg';
|
import deviceScreenIcon from './imgs/demos/icon-demo-device-screen.jpg';
|
||||||
import logoIcon from 'url:./imgs/demos/icon-demo-logo.png';
|
import logoIcon from './imgs/demos/icon-demo-logo.png';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import SnackBarElement from '../../lib/SnackBar';
|
import SnackBarElement from '../../lib/SnackBar';
|
||||||
|
|
||||||
const demos = [
|
const demos = [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import RangeInputElement from '../../custom-els/RangeInput';
|
import RangeInputElement from '../../custom-els/RangeInput';
|
||||||
import '../../custom-els/RangeInput';
|
import '../../custom-els/RangeInput';
|
||||||
import { linkRef, bind } from '../../lib/initial-util';
|
import { linkRef, bind } from '../../lib/initial-util';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import prettyBytes from 'pretty-bytes';
|
import * as prettyBytes from 'pretty-bytes';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
blob: Blob;
|
blob: Blob;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { h, Component, ComponentChildren, ComponentChild } from 'preact';
|
import { h, Component, ComponentChildren, ComponentChild } from 'preact';
|
||||||
|
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
import FileSize from './FileSize';
|
import FileSize from './FileSize';
|
||||||
import { DownloadIcon, CopyAcrossIcon, CopyAcrossIconProps } from '../../lib/icons';
|
import { DownloadIcon, CopyAcrossIcon, CopyAcrossIconProps } from '../../lib/icons';
|
||||||
import '../custom-els/LoadingSpinner';
|
import '../custom-els/LoadingSpinner';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import * as style from './style.module.scss';
|
import * as style from './style.scss';
|
||||||
|
|
||||||
interface Props extends JSX.HTMLAttributes {
|
interface Props extends JSX.HTMLAttributes {
|
||||||
large?: boolean;
|
large?: boolean;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import PointerTracker from 'pointer-tracker';
|
import PointerTracker from 'pointer-tracker';
|
||||||
import { bind } from '../../lib/initial-util';
|
import { bind } from '../../lib/initial-util';
|
||||||
import * as style from './styles.module.css';
|
import * as style from './styles.css';
|
||||||
|
|
||||||
const RETARGETED_EVENTS = ['focus', 'blur'];
|
const RETARGETED_EVENTS = ['focus', 'blur'];
|
||||||
const UPDATE_EVENTS = ['input', 'change'];
|
const UPDATE_EVENTS = ['input', 'change'];
|
||||||
|
|||||||
@@ -12,6 +12,5 @@
|
|||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="./index.ts"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
17
src/index.ts
17
src/index.ts
@@ -1,27 +1,18 @@
|
|||||||
declare module '@webcomponents/custom-elements';
|
declare module '@webcomponents/custom-elements';
|
||||||
|
|
||||||
// Patch Worker to ignore `importScripts("x.css")` generated by Parcel:
|
|
||||||
const W = self.Worker;
|
|
||||||
self.Worker = function (url: string | URL, options?: WorkerOptions) {
|
|
||||||
const code = `
|
|
||||||
importScripts=(function(){
|
|
||||||
return this.apply(self,[].slice.call(arguments).map(function(x){return !/\\.css$/i.test(x) && new URL(x,self.url).href}).filter(Boolean))
|
|
||||||
}).bind(importScripts);importScripts(self.url=${JSON.stringify(url)})
|
|
||||||
`.trim();
|
|
||||||
return new W(URL.createObjectURL(new Blob([code], { type: 'text/javascript' })), options);
|
|
||||||
} as any as (typeof Worker);
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
require('./init-app.tsx');
|
require('./init-app.tsx');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!('customElements' in self)) {
|
if (!('customElements' in self)) {
|
||||||
import('@webcomponents/custom-elements').then(init);
|
import(
|
||||||
|
/* webpackChunkName: "wc-polyfill" */
|
||||||
|
'@webcomponents/custom-elements').then(init);
|
||||||
} else {
|
} else {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof process.env.PRERENDER === 'undefined') {
|
if (typeof PRERENDER === 'undefined') {
|
||||||
// Determine the current display mode.
|
// Determine the current display mode.
|
||||||
let displayMode = 'browser';
|
let displayMode = 'browser';
|
||||||
const mqStandAlone = '(display-mode: standalone)';
|
const mqStandAlone = '(display-mode: standalone)';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { h, render } from 'preact';
|
import { h, render } from 'preact';
|
||||||
import './lib/fix-pmc.mjs';
|
import './lib/fix-pmc';
|
||||||
import './style/index.scss';
|
import './style';
|
||||||
import App from './components/App';
|
import App from './components/App';
|
||||||
|
|
||||||
// Find the outermost Element in our server-rendered HTML structure.
|
// Find the outermost Element in our server-rendered HTML structure.
|
||||||
@@ -14,8 +14,12 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
// Enable support for React DevTools and some helpful console warnings:
|
// Enable support for React DevTools and some helpful console warnings:
|
||||||
require('preact/debug');
|
require('preact/debug');
|
||||||
|
|
||||||
// Full HMR may not be working due to https://github.com/parcel-bundler/parcel/issues/5016
|
// When an update to any module is received, re-import the app and trigger a full re-render:
|
||||||
if (module.hot) {
|
module.hot.accept('./components/App', () => {
|
||||||
module.hot.accept();
|
// The linter doesn't like the capital A in App. It is wrong.
|
||||||
}
|
// tslint:disable-next-line variable-name
|
||||||
|
import('./components/App').then(({ default: App }) => {
|
||||||
|
root = render(<App />, document.body, root);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as style from './styles.module.css';
|
import * as style from './styles.css';
|
||||||
|
|
||||||
export interface SnackOptions {
|
export interface SnackOptions {
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
|||||||
@@ -60,9 +60,7 @@ export function getSharedImage(): Promise<File> {
|
|||||||
/** Set up the service worker and monitor changes */
|
/** Set up the service worker and monitor changes */
|
||||||
export async function offliner(showSnack: SnackBarElement['showSnackbar']) {
|
export async function offliner(showSnack: SnackBarElement['showSnackbar']) {
|
||||||
// This needs to be a typeof because Webpack.
|
// This needs to be a typeof because Webpack.
|
||||||
if (process.env.PRERENDER) return;
|
if (typeof PRERENDER === 'boolean') return;
|
||||||
|
|
||||||
if (!navigator.serviceWorker) return;
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
navigator.serviceWorker.register('../sw');
|
navigator.serviceWorker.register('../sw');
|
||||||
|
|||||||
16
src/missing-types.d.ts
vendored
16
src/missing-types.d.ts
vendored
@@ -2,13 +2,6 @@ interface CanvasRenderingContext2D {
|
|||||||
filter: string;
|
filter: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '*.module.scss' {
|
|
||||||
const classNameMapping: Record<string, string> & {
|
|
||||||
default: Record<string, string>
|
|
||||||
};
|
|
||||||
export = classNameMapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handling file-loader imports:
|
// Handling file-loader imports:
|
||||||
declare module '*.png' {
|
declare module '*.png' {
|
||||||
const content: string;
|
const content: string;
|
||||||
@@ -35,12 +28,7 @@ declare module '*.wasm' {
|
|||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'url:*' {
|
declare module 'url-loader!*' {
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'data-url:*' {
|
|
||||||
const value: string;
|
const value: string;
|
||||||
export default value;
|
export default value;
|
||||||
}
|
}
|
||||||
@@ -53,5 +41,5 @@ declare var ga: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface Navigator {
|
interface Navigator {
|
||||||
readonly standalone: boolean;
|
readonly standalone: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import webpDataUrl from 'url:../codecs/tiny.webp';
|
import webpDataUrl from 'url-loader!../codecs/tiny.webp';
|
||||||
|
|
||||||
// Give TypeScript the correct global.
|
// Give TypeScript the correct global.
|
||||||
declare var self: ServiceWorkerGlobalScope;
|
declare var self: ServiceWorkerGlobalScope;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
|
|||||||
Reference in New Issue
Block a user