From 4361728b6d8d3586389b60e16bcc63b66c02d43b Mon Sep 17 00:00:00 2001 From: xororz Date: Fri, 12 Apr 2024 04:02:42 -0400 Subject: [PATCH] code init --- .gitignore | 34 ++ README.md | 33 ++ env.d.ts | 1 + index.html | 21 + package-lock.json | 1340 +++++++++++++++++++++++++++++++++++++++++++ package.json | 28 + public/favicon.ico | Bin 0 -> 40215 bytes src/App.vue | 736 ++++++++++++++++++++++++ src/assets/main.css | 248 ++++++++ src/image.ts | 30 + src/main.ts | 6 + src/upscale.ts | 42 ++ src/vue-shim.d.ts | 5 + src/worker.js | 360 ++++++++++++ tsconfig.app.json | 14 + tsconfig.json | 11 + tsconfig.node.json | 19 + vite.config.ts | 16 + 18 files changed, 2944 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 env.d.ts create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon.ico create mode 100644 src/App.vue create mode 100644 src/assets/main.css create mode 100644 src/image.ts create mode 100644 src/main.ts create mode 100644 src/upscale.ts create mode 100644 src/vue-shim.d.ts create mode 100644 src/worker.js create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d53d81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +lib +demo +realesrgan +*.ttf +.vscode +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca8dcfd --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# canvastest + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/index.html b/index.html new file mode 100644 index 0000000..da56b2b --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + + + Run Super Resulotion in Your Browser + + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..08c4a47 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1340 @@ +{ + "name": "canvastest", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "canvastest", + "version": "0.0.0", + "dependencies": { + "vue": "^3.4.21" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.2", + "@types/node": "^20.11.28", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/tsconfig": "^0.5.1", + "npm-run-all2": "^6.1.2", + "typescript": "~5.4.0", + "vite": "^5.1.6", + "vue-tsc": "^2.0.6" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz", + "integrity": "sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.1.tgz", + "integrity": "sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz", + "integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.1.tgz", + "integrity": "sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.1.tgz", + "integrity": "sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz", + "integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.1.tgz", + "integrity": "sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.1.tgz", + "integrity": "sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==", + "cpu": [ + "ppc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.1.tgz", + "integrity": "sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.1.tgz", + "integrity": "sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz", + "integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.1.tgz", + "integrity": "sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.1.tgz", + "integrity": "sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.1.tgz", + "integrity": "sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.1.tgz", + "integrity": "sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", + "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.6.tgz", + "integrity": "sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.2.0-alpha.6", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.0-alpha.6.tgz", + "integrity": "sha512-GmT28LX2w4x82uuQqNN/P94VOCsZRHBbGcGe+5bFtA2hbIbH6f8tFdMfgXFtyhbft/pj6f3xl37xe+t+nomLIA==", + "dev": true, + "dependencies": { + "@volar/source-map": "2.2.0-alpha.6" + } + }, + "node_modules/@volar/source-map": { + "version": "2.2.0-alpha.6", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.0-alpha.6.tgz", + "integrity": "sha512-EztD2zoUopETY+ZCUZAGUHKgj4gOkY/2WnaOS+RSTc56xm85miSA4qOBS8Lt1Ruu5vV52WIZKHW/R9PbjkZWFA==", + "dev": true, + "dependencies": { + "muggle-string": "^0.4.0" + } + }, + "node_modules/@volar/typescript": { + "version": "2.2.0-alpha.6", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.0-alpha.6.tgz", + "integrity": "sha512-wTr0jO3wVXQ9FjBbWE2iX8GgDoiHp1Nttsb+tKk5IeUUb6f1uOjyeIXuS4KfeMBpCufthRO2st2O2uatAs/UXQ==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.2.0-alpha.6", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/shared": "3.4.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", + "dependencies": { + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", + "dependencies": { + "@babel/parser": "^7.23.9", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/language-core": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.11.tgz", + "integrity": "sha512-5ivg8Vem/yckzXI3L3n0mdKBPRcHSlsGt6/dpbEx42PcH3MIHAjSAJBYvENXeWJxv2ClQc8BS2mH1Ho2U7jZig==", + "dev": true, + "dependencies": { + "@volar/language-core": "~2.2.0-alpha.6", + "@vue/compiler-dom": "^3.4.0", + "@vue/shared": "^3.4.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", + "dependencies": { + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", + "dependencies": { + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", + "dependencies": { + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", + "dependencies": { + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "vue": "3.4.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" + }, + "node_modules/@vue/tsconfig": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", + "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz", + "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.2.tgz", + "integrity": "sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^3.0.2", + "shell-quote": "^1.7.3" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/rollup": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.1.tgz", + "integrity": "sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.14.1", + "@rollup/rollup-android-arm64": "4.14.1", + "@rollup/rollup-darwin-arm64": "4.14.1", + "@rollup/rollup-darwin-x64": "4.14.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.14.1", + "@rollup/rollup-linux-arm64-gnu": "4.14.1", + "@rollup/rollup-linux-arm64-musl": "4.14.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.14.1", + "@rollup/rollup-linux-riscv64-gnu": "4.14.1", + "@rollup/rollup-linux-s390x-gnu": "4.14.1", + "@rollup/rollup-linux-x64-gnu": "4.14.1", + "@rollup/rollup-linux-x64-musl": "4.14.1", + "@rollup/rollup-win32-arm64-msvc": "4.14.1", + "@rollup/rollup-win32-ia32-msvc": "4.14.1", + "@rollup/rollup-win32-x64-msvc": "4.14.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/vite": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", + "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", + "dependencies": { + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.11.tgz", + "integrity": "sha512-dl5MEU4VGZdQFGBnKfPpAfV3SQmBDWs9o4YhUPvDmwk+zmb/RprzFJK2sagR6EWazogZhXENvykd3wBXWS9kng==", + "dev": true, + "dependencies": { + "@volar/typescript": "~2.2.0-alpha.6", + "@vue/language-core": "2.0.11", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a14e9d8 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "canvastest", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force" + }, + "dependencies": { + "@tensorflow/tfjs": "^4.17.0", + "@tensorflow/tfjs-backend-webgpu": "^4.17.0", + "vue": "^3.4.21" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.2", + "@types/node": "^20.11.28", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/tsconfig": "^0.5.1", + "npm-run-all2": "^6.1.2", + "typescript": "~5.4.0", + "vite": "^5.1.6", + "vue-tsc": "^2.0.6" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b588231eda6225f182acfb99da1b2b06b394b20a GIT binary patch literal 40215 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 +
+
+
SuperResolution in Your Browser
+ favicon +
+ + + +
+
+
{{ info }}
+
+ +
+
+
+
+ Model + +
+
+ Run on + +
+
+ + +
+
+
+ + + + +
+
+
+ + + + +
+
No ideas? Try one of these:
+
+
+ demo + demo + demo +
+
+
+ +
+ + + diff --git a/src/assets/main.css b/src/assets/main.css new file mode 100644 index 0000000..3c64d79 --- /dev/null +++ b/src/assets/main.css @@ -0,0 +1,248 @@ +@font-face { + font-family: "Roboto-Bold"; + src: url("/src/assets/Roboto-Bold.ttf") format("truetype"); +} +body, +html, +#app { + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; +} +.canvas-container { + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + height: 100%; + display: block; +} +.bg { + background-color: #ffffff; + background-image: linear-gradient( + 45deg, + #f3f3f3 25%, + transparent 25%, + transparent 75%, + #f3f3f3 75%, + #f3f3f3 + ), + linear-gradient( + 45deg, + #f3f3f3 25%, + #ffffff 25%, + #ffffff 75%, + #f3f3f3 75%, + #f3f3f3 + ); + background-size: 20px 20px; + background-position: 0 0, 10px 10px; +} +.bg.dark { + background-color: #313131; + background-image: linear-gradient( + 45deg, + #333333 25%, + transparent 25%, + transparent 75%, + #333333 75%, + #333333 + ), + linear-gradient( + 45deg, + #333333 25%, + #313131 25%, + #313131 75%, + #333333 75%, + #333333 + ); + background-size: 20px 20px; + background-position: 0 0, 10px 10px; +} +canvas { + height: 100vh; +} +.title { + position: fixed; + top: 6%; + left: 50%; + width: 80%; + transform: translate(-50%, 0%); + text-align: center; + color: brown; + font-size: 32px; + font-family: "Roboto-Bold"; + font-weight: 700; + font-style: normal; /* font-weight: 900;font-style: normal; */ + margin: 10px; +} + +.upload-button { + background-color: #ff568a; + border-width: 0px; + border-radius: 50%; + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -60%); + z-index: 10; + width: 200px; + height: 200px; + display: flex; + justify-content: center; + align-items: center; +} +.upload-button:hover { + cursor: pointer; +} +.upload-container { + width: 100px; + height: 100px; +} +.bottom-svg { + width: 100%; + position: absolute; + bottom: -20px; + left: 50%; + transform: translate(-50%, 0%); + z-index: 10; +} +.placeholder { + height: 300px; + background-color: #009aff; +} +.demo { + margin-top: -10px; + padding: 20px; + height: 200px; + background-color: #009aff; + text-align: center; + color: #fff; + font-size: 20px; + font-family: "Roboto-Bold"; +} +.favicon:hover { + cursor: pointer; +} +.demoimg { + width: 80px; + height: 80px; + border-radius: 50%; + margin: 12px; +} +.demoimg:hover { + cursor: pointer; +} +.description { + display: inline-block; + color: white; + min-width: 60px; + font-family: "Roboto-Bold"; +} +select { + width: 120px; + background-color: #1d1d1d; + color: white; + font-size: 16px; + font-family: "Roboto-Bold"; + border: none; + border-radius: 5px; + padding: 5px; + margin: 5px; +} +.run-button { + margin-left: 20px; + width: 40px; + height: 40px; + background-color: #1d90ee; + border: none; + border-radius: 25px; + padding: 5px; + margin: 5px; + display: inline-block; + margin-left: 20px; +} +.run-button:hover { + cursor: pointer; +} +.save-button { + margin-left: 20px; + width: 40px; + height: 40px; + background-color: rgb(157, 202, 90); + border: none; + border-radius: 25px; + padding: 5px; + margin: 5px; + display: inline-block; + margin-left: 20px; +} +.save-button:hover { + cursor: pointer; +} +.goback { + position: absolute; + top: 10px; + left: 10px; + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + z-index: 10; + background-color: #d21d5a; + border: none; + border-radius: 20px; + padding: 5px; + margin: 5px; +} +.goback:hover { + cursor: pointer; +} +.floating-menu { + position: absolute; + background-color: #1d1d1d; + border-radius: 20px; + color: white; + max-width: 100%; + width: 280px; + padding: 20px; + bottom: 25px; + left: 50%; + transform: translate(-50%, 0%); + z-index: 10; + display: flex; + justify-content: center; + align-items: center; + transition: all 0.5s ease; +} +.dragLine { + position: fixed; + top: 0; + bottom: 0; + left: 50%; + width: 9px; + transform: translate(-100%, 0); + background-color: rgba(0, 0, 0, 0.6); + display: flex; + justify-content: center; + align-items: center; +} +.dragLine:hover { + cursor: ew-resize; +} +.dragBall { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 56px; + height: 56px; + background-color: rgba(0, 0, 0, 0.9); + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/image.ts b/src/image.ts new file mode 100644 index 0000000..6cc9b4e --- /dev/null +++ b/src/image.ts @@ -0,0 +1,30 @@ +export default class Image { + width: number; + height: number; + data: Uint8Array; + constructor(width: number, height: number) { + this.width = width; + this.height = height; + this.data = new Uint8Array(width * height * 4); + } + getImageCrop( + x: number, + y: number, + image: Image, + x1: number, + y1: number, + x2: number, + y2: number + ) { + for (let j = y1; j < y2; j++) { + for (let i = x1; i < x2; i++) { + let index = (y + j - y1) * this.width * 4 + (x + i - x1) * 4; + let imageIndex = j * image.width * 4 + i * 4; + this.data[index] = image.data[imageIndex]; + this.data[index + 1] = image.data[imageIndex + 1]; + this.data[index + 2] = image.data[imageIndex + 2]; + this.data[index + 3] = image.data[imageIndex + 3]; + } + } + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..9d71566 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,6 @@ +import "./assets/main.css"; + +import { createApp } from "vue"; +import App from "./App.vue"; + +createApp(App).mount("#app"); diff --git a/src/upscale.ts b/src/upscale.ts new file mode 100644 index 0000000..f4edcab --- /dev/null +++ b/src/upscale.ts @@ -0,0 +1,42 @@ +import * as tf from "@tensorflow/tfjs"; +import Image from "./image"; + +export default async function upscale( + image: Image, + model: any +): Promise { + let tensor = img2tensor(image); + let result = model.predict(tensor) as tf.Tensor; + let resultImage = await tensor2img(result); + return resultImage; +} + +function img2tensor(image: Image): tf.Tensor { + let arr = new Float32Array(image.width * image.height * 3); + for (let i = 0; i < image.width * image.height; i++) { + arr[i * 3] = image.data[i * 4] / 255; + arr[i * 3 + 1] = image.data[i * 4 + 1] / 255; + arr[i * 3 + 2] = image.data[i * 4 + 2] / 255; + } + let tensor = tf.tensor4d(arr, [1, image.height, image.width, 3]); + return tensor; +} + +async function tensor2img(tensor: tf.Tensor): Promise { + let [_, height, width, __] = tensor.shape; + let arr = await tensor.data(); + let clipped = new Uint8Array( + arr.map((x) => { + x = Math.min(1, Math.max(0, x)); + return Math.floor(x * 255); + }) + ); + let image = new Image(width, height); + for (let i = 0; i < width * height; i++) { + image.data[i * 4] = clipped[i * 3]; + image.data[i * 4 + 1] = clipped[i * 3 + 1]; + image.data[i * 4 + 2] = clipped[i * 3 + 2]; + image.data[i * 4 + 3] = 255; + } + return image; +} diff --git a/src/vue-shim.d.ts b/src/vue-shim.d.ts new file mode 100644 index 0000000..daba9b9 --- /dev/null +++ b/src/vue-shim.d.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/src/worker.js b/src/worker.js new file mode 100644 index 0000000..5a818f1 --- /dev/null +++ b/src/worker.js @@ -0,0 +1,360 @@ +import * as tf from "@tensorflow/tfjs"; +import "@tensorflow/tfjs-backend-webgpu"; +import Img from "./image"; +import upscale from "./upscale"; + +self.addEventListener("message", async (e) => { + const { data } = e; + + let model_url = ""; + if (data?.model === "anime_4x") { + model_url = `/realesrgan/anime_4x/model.json`; + } + if (data?.model === "anime_4x_plus") { + model_url = `/realesrgan/anime_4x_plus/model.json`; + } + if (data?.model === "general") { + model_url = `/realesrgan/general/model.json`; + } + if (data?.model === "realx4plus") { + model_url = `/realesrgan/realx4plus/model.json`; + } + if (!(await tf.setBackend(data?.backend || "webgl"))) { + postMessage({ + alertmsg: `${data?.backend} is not supported in your browser.`, + }); + return; + } + let model; + try { + model = await tf.loadGraphModel(`indexeddb://${data?.model}`); + console.log("Model loaded successfully"); + // self.postMessage({ info: "Model loaded from cache" }); + } catch (error) { + self.postMessage({ info: "Downloading model" }); + model = await (async () => { + const fetchedModel = await tf.loadGraphModel(model_url); + await fetchedModel.save(`indexeddb://${data?.model}`); + return fetchedModel; + })(); + } + if (!model) { + return; + } + const input = new Img(data.width, data.height); + input.data = data.input; + let hasAlpha = data.hasAlpha; + function sendprogress(progress) { + if (hasAlpha) { + self.postMessage({ + progress: progress, + info: `Processing Alpha ${progress.toFixed(2)}%`, + }); + return; + } + self.postMessage({ + progress: progress, + info: `Processing ${progress.toFixed(2)}%`, + }); + } + async function enlargeImage( + model, + inputImg, + factor = 4, + tilesize = 32, + padsize = 8 + ) { + if (hasAlpha) { + tilesize = 16; + padsize = 4; + } + const width = inputImg.width; + const height = inputImg.height; + const output = new Img(width * factor, height * factor); + const total = Math.ceil(width / tilesize) * Math.ceil(height / tilesize); + let current = 0; + let useModel = new Array(total).fill(false); + if (hasAlpha) { + for (let i = 0; i < width; i += tilesize) { + for (let j = 0; j < height; j += tilesize) { + const x1 = Math.max(i, 0); + const y1 = Math.max(j, 0); + const x2 = Math.min(i + tilesize, width); + const y2 = Math.min(j + tilesize, height); + const tile = new Img(x2 - x1, y2 - y1); + tile.getImageCrop(0, 0, input, x1, y1, x2, y2); + for (let k = 4; k < tile.data.length; k += 4) { + if (tile.data[k + 3] !== tile.data[3]) { + useModel[current] = true; + break; + } + } + if (useModel[current]) { + current++; + continue; + } + let scaled = new Img(tile.width * factor, tile.height * factor); + for (let k = 0; k < scaled.data.length; k += 4) { + scaled.data[k] = tile.data[3]; + scaled.data[k + 1] = tile.data[3]; + scaled.data[k + 2] = tile.data[3]; + } + output.getImageCrop( + i * factor, + j * factor, + scaled, + 0, + 0, + scaled.width, + scaled.height + ); + current++; + } + } + current = 0; + for (let i = 0; i < width; i += tilesize) { + for (let j = 0; j < height; j += tilesize) { + if (!useModel[current]) { + current++; + let progress = (current / total) * 100; + sendprogress(progress); + continue; + } + const x1 = Math.max(i - padsize, 0); + const y1 = Math.max(j - padsize, 0); + const x2 = Math.min(i + tilesize + padsize, width); + const y2 = Math.min(j + tilesize + padsize, height); + const pad_left = i - x1; + const pad_top = j - y1; + const pad_right = Math.max(0, x2 - (i + tilesize)); + const pad_bottom = Math.max(0, y2 - (j + tilesize)); + const tile = new Img(x2 - x1, y2 - y1); + tile.getImageCrop(0, 0, input, x1, y1, x2, y2); + let scaled = await upscale(tile, model); + output.getImageCrop( + i * factor, + j * factor, + scaled, + pad_left * factor, + pad_top * factor, + scaled.width - pad_right * factor, + scaled.height - pad_bottom * factor + ); + // console.log(i, j, x2 - x1, y2 - y1); + current++; + let progress = (current / total) * 100; + sendprogress(progress); + } + } + } else { + for (let i = 0; i < width; i += tilesize) { + for (let j = 0; j < height; j += tilesize) { + const x1 = Math.max(i - padsize, 0); + const y1 = Math.max(j - padsize, 0); + const x2 = Math.min(i + tilesize + padsize, width); + const y2 = Math.min(j + tilesize + padsize, height); + const pad_left = i - x1; + const pad_top = j - y1; + const pad_right = Math.max(0, x2 - (i + tilesize)); + const pad_bottom = Math.max(0, y2 - (j + tilesize)); + const tile = new Img(x2 - x1, y2 - y1); + tile.getImageCrop(0, 0, input, x1, y1, x2, y2); + let scaled = await upscale(tile, model); + output.getImageCrop( + i * factor, + j * factor, + scaled, + pad_left * factor, + pad_top * factor, + scaled.width - pad_right * factor, + scaled.height - pad_bottom * factor + ); + // console.log(i, j, x2 - x1, y2 - y1); + current++; + let progress = (current / total) * 100; + sendprogress(progress); + } + } + } + return output; + } + async function enlargeImageWithFixedInput( + model, + inputImg, + factor = 4, + input_size = 64, + min_lap = 12 + ) { + const width = inputImg.width; + const height = inputImg.height; + const output = new Img(width * factor, height * factor); + let num_x = 1; + for (; (input_size * num_x - width) / (num_x - 1) < min_lap; num_x++); + let num_y = 1; + for (; (input_size * num_y - height) / (num_y - 1) < min_lap; num_y++); + const locs_x = new Array(num_x); + const locs_y = new Array(num_y); + const pad_left = new Array(num_x); + const pad_top = new Array(num_y); + const pad_right = new Array(num_x); + const pad_bottom = new Array(num_y); + const total_lap_x = input_size * num_x - width; + const total_lap_y = input_size * num_y - height; + const base_lap_x = Math.floor(total_lap_x / (num_x - 1)); + const base_lap_y = Math.floor(total_lap_y / (num_y - 1)); + const extra_lap_x = total_lap_x - base_lap_x * (num_x - 1); + const extra_lap_y = total_lap_y - base_lap_y * (num_y - 1); + locs_x[0] = 0; + for (let i = 1; i < num_x; i++) { + if (i <= extra_lap_x) { + locs_x[i] = locs_x[i - 1] + input_size - base_lap_x - 1; + } else { + locs_x[i] = locs_x[i - 1] + input_size - base_lap_x; + } + } + locs_y[0] = 0; + for (let i = 1; i < num_y; i++) { + if (i <= extra_lap_y) { + locs_y[i] = locs_y[i - 1] + input_size - base_lap_y - 1; + } else { + locs_y[i] = locs_y[i - 1] + input_size - base_lap_y; + } + } + pad_left[0] = 0; + pad_top[0] = 0; + pad_right[num_x - 1] = 0; + pad_bottom[num_y - 1] = 0; + for (let i = 1; i < num_x; i++) { + pad_left[i] = Math.floor((locs_x[i - 1] + input_size - locs_x[i]) / 2); + } + for (let i = 1; i < num_y; i++) { + pad_top[i] = Math.floor((locs_y[i - 1] + input_size - locs_y[i]) / 2); + } + for (let i = 0; i < num_x - 1; i++) { + pad_right[i] = locs_x[i] + input_size - locs_x[i + 1] - pad_left[i + 1]; + } + for (let i = 0; i < num_y - 1; i++) { + pad_bottom[i] = locs_y[i] + input_size - locs_y[i + 1] - pad_top[i + 1]; + } + const total = num_x * num_y; + let current = 0; + let useModel = new Array(total).fill(false); + if (hasAlpha) { + for (let i = 0; i < num_x; i++) { + for (let j = 0; j < num_y; j++) { + const x1 = locs_x[i]; + const y1 = locs_y[j]; + const x2 = locs_x[i] + input_size; + const y2 = locs_y[j] + input_size; + const tile = new Img(input_size, input_size); + tile.getImageCrop(0, 0, inputImg, x1, y1, x2, y2); + let scaled; + for (let k = 4; k < tile.data.length; k += 4) { + if (tile.data[k + 3] !== tile.data[3]) { + useModel[current] = true; + break; + } + } + if (useModel[current]) { + current++; + continue; + } + scaled = new Img(tile.width * factor, tile.height * factor); + for (let k = 0; k < scaled.data.length; k += 4) { + scaled.data[k] = tile.data[3]; + scaled.data[k + 1] = tile.data[3]; + scaled.data[k + 2] = tile.data[3]; + } + output.getImageCrop( + (x1 + pad_left[i]) * factor, + (y1 + pad_top[j]) * factor, + scaled, + pad_left[i] * factor, + pad_top[j] * factor, + scaled.width - pad_right[i] * factor, + scaled.height - pad_bottom[j] * factor + ); + // console.log(i, j, x2 - x1, y2 - y1); + current++; + } + } + current = 0; + for (let i = 0; i < num_x; i++) { + for (let j = 0; j < num_y; j++) { + if (!useModel[current]) { + current++; + let progress = (current / total) * 100; + sendprogress(progress); + continue; + } + const x1 = locs_x[i]; + const y1 = locs_y[j]; + const x2 = locs_x[i] + input_size; + const y2 = locs_y[j] + input_size; + const tile = new Img(input_size, input_size); + tile.getImageCrop(0, 0, inputImg, x1, y1, x2, y2); + let scaled = await upscale(tile, model); + output.getImageCrop( + (x1 + pad_left[i]) * factor, + (y1 + pad_top[j]) * factor, + scaled, + pad_left[i] * factor, + pad_top[j] * factor, + scaled.width - pad_right[i] * factor, + scaled.height - pad_bottom[j] * factor + ); + // console.log(i, j, x2 - x1, y2 - y1); + current++; + let progress = (current / total) * 100; + sendprogress(progress); + } + } + } else { + for (let i = 0; i < num_x; i++) { + for (let j = 0; j < num_y; j++) { + const x1 = locs_x[i]; + const y1 = locs_y[j]; + const x2 = locs_x[i] + input_size; + const y2 = locs_y[j] + input_size; + const tile = new Img(input_size, input_size); + tile.getImageCrop(0, 0, inputImg, x1, y1, x2, y2); + let scaled = await upscale(tile, model); + output.getImageCrop( + (x1 + pad_left[i]) * factor, + (y1 + pad_top[j]) * factor, + scaled, + pad_left[i] * factor, + pad_top[j] * factor, + scaled.width - pad_right[i] * factor, + scaled.height - pad_bottom[j] * factor + ); + // console.log(i, j, x2 - x1, y2 - y1); + current++; + let progress = (current / total) * 100; + sendprogress(progress); + } + } + } + return output; + } + let factor = data?.factor || 4; + const start = Date.now(); + let output; + try { + if (data?.fixed) { + output = await enlargeImageWithFixedInput(model, input, factor); + } else { + output = await enlargeImage(model, input, factor); + } + } catch (e) { + postMessage({ alertmsg: e.toString() }); + } + const end = Date.now(); + console.log("Time:", end - start); + postMessage({ + progress: 100, + done: true, + output: output, + info: `Processing image...`, + }); +}); diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +})