Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f81d2dd793 | ||
|
|
b8a81864ea | ||
|
|
efc8e5b3c8 | ||
|
|
76f23dade3 | ||
|
|
37036998d3 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -32,3 +32,5 @@ coverage
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
realesrgan
|
||||
realcugan
|
||||
|
||||
16
README.md
16
README.md
@@ -1,6 +1,6 @@
|
||||
# web-realesrgan
|
||||
|
||||
Run Real-ESRGAN in the browser with tensorflow.js
|
||||
Run Real-ESRGAN/Real-CUGAN in the browser with tensorflow.js
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -21,6 +21,16 @@ Sure, PNG with alpha channel is supported.
|
||||
|
||||
All models are quantized to FP16, which reduces the size of the model download and has no noticeable difference in performance compared to FP32 models. However, currently, the computation speed of FP16 is the same as FP32. Future updates from the TensorFlow.js team are expected to improve FP16 computation performance on WebGPU.
|
||||
|
||||
### 🚀️ ️Advantages
|
||||
|
||||
**Accessible Anywhere**: The tool can be conveniently run on any device, such as a mobile phone📱️, without needing to download or install any software. This makes it possible to upscale images anytime, anywhere, directly in your browser.
|
||||
|
||||
### ⚠️️ Limitations
|
||||
|
||||
**Performance Gap**: Even with WebGPU enabled, the performance of running models in the browser is slower than running them locally. WebGPU’s speed is approximately half of the speed you’d achieve with local execution. On local devices, FP16 computation provides significant acceleration, whereas in tfjs-webgpu for now, FP16 and FP32 run at the same speed.
|
||||
|
||||
If you need to upscale a lot of images, it is recommended to download and use the official Real-ESRGAN and Real-CUGAN repositories for local execution.
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
@@ -28,6 +38,10 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
WebGPU cannot be used over HTTP. If you're developing this project locally, you can use OpenSSL to self-sign a certificate.
|
||||
|
||||
See https://developer.chrome.com/docs/web-platform/webgpu/troubleshooting-tips
|
||||
|
||||
## Models
|
||||
|
||||
The first run will download the models and cache them in the browser indexedDB. No need to download them again.
|
||||
|
||||
186
package-lock.json
generated
186
package-lock.json
generated
@@ -8,8 +8,9 @@
|
||||
"name": "canvastest",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs": "^4.17.0",
|
||||
"@tensorflow/tfjs-backend-webgpu": "^4.17.0",
|
||||
"@tensorflow/tfjs": "^4.22.0",
|
||||
"@tensorflow/tfjs-backend-webgpu": "^4.22.0",
|
||||
"@tensorflow/tfjs-core": "^4.22.0",
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -603,16 +604,17 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.21.0.tgz",
|
||||
"integrity": "sha512-7D/+H150ptvt+POMbsME3WlIvLiuBR2rCC2Z0hOKKb/5Ygkj7xsp/K2HzOvUj0g0yjk+utkU45QEYhnhjnbHRA==",
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-4.22.0.tgz",
|
||||
"integrity": "sha512-0TrIrXs6/b7FLhLVNmfh8Sah6JgjBPH4mZ8JGb7NU6WW+cx00qK5BcAZxw7NCzxj6N8MRAIfHq+oNbPUNG5VAg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs-backend-cpu": "4.21.0",
|
||||
"@tensorflow/tfjs-backend-webgl": "4.21.0",
|
||||
"@tensorflow/tfjs-converter": "4.21.0",
|
||||
"@tensorflow/tfjs-core": "4.21.0",
|
||||
"@tensorflow/tfjs-data": "4.21.0",
|
||||
"@tensorflow/tfjs-layers": "4.21.0",
|
||||
"@tensorflow/tfjs-backend-cpu": "4.22.0",
|
||||
"@tensorflow/tfjs-backend-webgl": "4.22.0",
|
||||
"@tensorflow/tfjs-converter": "4.22.0",
|
||||
"@tensorflow/tfjs-core": "4.22.0",
|
||||
"@tensorflow/tfjs-data": "4.22.0",
|
||||
"@tensorflow/tfjs-layers": "4.22.0",
|
||||
"argparse": "^1.0.10",
|
||||
"chalk": "^4.1.0",
|
||||
"core-js": "3.29.1",
|
||||
@@ -624,9 +626,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-backend-cpu": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.17.0.tgz",
|
||||
"integrity": "sha512-2VSCHnX9qhYTjw9HiVwTBSnRVlntKXeBlK7aSVsmZfHGwWE2faErTtO7bWmqNqw0U7gyznJbVAjlow/p+0RNGw==",
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.22.0.tgz",
|
||||
"integrity": "sha512-1u0FmuLGuRAi8D2c3cocHTASGXOmHc/4OvoVDENJayjYkS119fcTcQf4iHrtLthWyDIPy3JiPhRrZQC9EwnhLw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"seedrandom": "^3.0.5"
|
||||
@@ -635,25 +638,53 @@
|
||||
"yarn": ">= 1.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.17.0"
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-backend-webgl": {
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.22.0.tgz",
|
||||
"integrity": "sha512-H535XtZWnWgNwSzv538czjVlbJebDl5QTMOth4RXr2p/kJ1qSIXE0vZvEtO+5EC9b00SvhplECny2yDewQb/Yg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs-backend-cpu": "4.22.0",
|
||||
"@types/offscreencanvas": "~2019.3.0",
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"yarn": ">= 1.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-backend-webgpu": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgpu/-/tfjs-backend-webgpu-4.17.0.tgz",
|
||||
"integrity": "sha512-LUEUU9ZT3/LTEzV3ht/i7QaQbe9ferrefVttL/2DS9NbgzgTa/lggMo4R8Mr49/PTKrvL1ou+61/rHn1virahg==",
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgpu/-/tfjs-backend-webgpu-4.22.0.tgz",
|
||||
"integrity": "sha512-lvIc7Af4Tl2BCdYp43iQmSCRq3asaKT0q2xaErphXiUZ+jqeB0bQa0ZvQys1Xatvto0U4/c90DVsHPfvkn5ftg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs-backend-cpu": "4.17.0"
|
||||
"@tensorflow/tfjs-backend-cpu": "4.22.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.17.0"
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-converter": {
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.22.0.tgz",
|
||||
"integrity": "sha512-PT43MGlnzIo+YfbsjM79Lxk9lOq6uUwZuCc8rrp0hfpLjF6Jv8jS84u2jFb+WpUeuF4K33ZDNx8CjiYrGQ2trQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-core": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.17.0.tgz",
|
||||
"integrity": "sha512-v9Q5430EnRpyhWNd9LVgXadciKvxLiq+sTrLKRowh26BHyAsams4tZIgX3lFKjB7b90p+FYifVMcqLTTHgjGpQ==",
|
||||
"peer": true,
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.22.0.tgz",
|
||||
"integrity": "sha512-LEkOyzbknKFoWUwfkr59vSB68DMJ4cjwwHgicXN0DUi3a0Vh1Er3JQqCI1Hl86GGZQvY8ezVrtDIvqR1ZFW55A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/offscreencanvas": "~2019.7.0",
|
||||
@@ -668,93 +699,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs-core/node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
"integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-backend-cpu": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.21.0.tgz",
|
||||
"integrity": "sha512-yS9Oisg4L48N7ML6677ilv1eP5Jt59S74skSU1cCsM4yBAtH4DAn9b89/JtqBISh6JadanfX26b4HCWQvMvqFg==",
|
||||
"dependencies": {
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"yarn": ">= 1.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-backend-webgl": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.21.0.tgz",
|
||||
"integrity": "sha512-7k6mb7dd0uF9jI51iunF3rhEXjvR/a613kjWZ0Rj3o1COFrneyku2C7cRMZERWPhbgXZ+dF+j9MdpGIpgtShIQ==",
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs-backend-cpu": "4.21.0",
|
||||
"@types/offscreencanvas": "~2019.3.0",
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"yarn": ">= 1.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-converter": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-4.21.0.tgz",
|
||||
"integrity": "sha512-cUhU+F1lGx2qnKk/gRy8odBh0PZlFz0Dl71TG8LVnj0/g352DqiNrKXlKO/po9aWzP8x0KUGC3gNMSMJW+T0DA==",
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-core": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.21.0.tgz",
|
||||
"integrity": "sha512-ZbECwXps5wb9XXcGq4ZXvZDVjr5okc3I0+i/vU6bpQ+nVApyIrMiyEudP8f6vracVTvNmnlN62vUXoEsQb2F8g==",
|
||||
"dependencies": {
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/offscreencanvas": "~2019.7.0",
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"@webgpu/types": "0.1.38",
|
||||
"long": "4.0.0",
|
||||
"node-fetch": "~2.6.1",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"yarn": ">= 1.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-core/node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
"integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A=="
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-data": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.21.0.tgz",
|
||||
"integrity": "sha512-LpJ/vyQMwYHkcVCqIRg7IVVw13VBY7rNAiuhmKP9S5NP/2ye4KA8BJ4XwDIDgjCVQM7glK9L8bMav++xCDf7xA==",
|
||||
"node_modules/@tensorflow/tfjs-data": {
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-data/-/tfjs-data-4.22.0.tgz",
|
||||
"integrity": "sha512-dYmF3LihQIGvtgJrt382hSRH4S0QuAp2w1hXJI2+kOaEqo5HnUPG0k5KA6va+S1yUhx7UBToUKCBHeLHFQRV4w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/node-fetch": "^2.1.2",
|
||||
"node-fetch": "~2.6.1",
|
||||
"string_decoder": "^1.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.21.0",
|
||||
"@tensorflow/tfjs-core": "4.22.0",
|
||||
"seedrandom": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@tensorflow/tfjs/node_modules/@tensorflow/tfjs-layers": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.21.0.tgz",
|
||||
"integrity": "sha512-a8KaMYlY3+llvE9079nvASKpaaf8xpCMdOjbgn+eGhdOGOcY7QuFUkd/2odvnXDG8fK/jffE1LoNOlfYoBHC4w==",
|
||||
"node_modules/@tensorflow/tfjs-layers": {
|
||||
"version": "4.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-4.22.0.tgz",
|
||||
"integrity": "sha512-lybPj4ZNj9iIAPUj7a8ZW1hg8KQGfqWLlCZDi9eM/oNKCCAgchiyzx8OrYoWmRrB+AM6VNEeIT+2gZKg5ReihA==",
|
||||
"license": "Apache-2.0 AND MIT",
|
||||
"peerDependencies": {
|
||||
"@tensorflow/tfjs-core": "4.21.0"
|
||||
"@tensorflow/tfjs-core": "4.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node20": {
|
||||
@@ -783,9 +753,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
@@ -794,7 +765,8 @@
|
||||
"node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz",
|
||||
"integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q=="
|
||||
"integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/seedrandom": {
|
||||
"version": "2.4.34",
|
||||
@@ -997,7 +969,8 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
@@ -1073,6 +1046,7 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -1125,6 +1099,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -1200,6 +1175,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -1312,6 +1288,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -1320,6 +1297,7 @@
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
@@ -1554,7 +1532,8 @@
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/seedrandom": {
|
||||
"version": "3.0.5",
|
||||
@@ -1623,6 +1602,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
"type-check": "vue-tsc --build --force"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tensorflow/tfjs": "^4.17.0",
|
||||
"@tensorflow/tfjs-backend-webgpu": "^4.17.0",
|
||||
"@tensorflow/tfjs": "^4.22.0",
|
||||
"@tensorflow/tfjs-backend-webgpu": "^4.22.0",
|
||||
"@tensorflow/tfjs-core": "^4.22.0",
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 145 KiB |
79
src/image.ts
79
src/image.ts
@@ -20,15 +20,76 @@ export default class Image {
|
||||
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];
|
||||
}
|
||||
const width = x2 - x1;
|
||||
for (let j = 0; j < y2 - y1; j++) {
|
||||
const destIndex = (y + j) * this.width * 4 + x * 4;
|
||||
const srcIndex = (y1 + j) * image.width * 4 + x1 * 4;
|
||||
this.data.set(
|
||||
image.data.subarray(srcIndex, srcIndex + width * 4),
|
||||
destIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
padToTileSize(tileSize: number) {
|
||||
let newWidth = this.width;
|
||||
let newHeight = this.height;
|
||||
if (this.width < tileSize) {
|
||||
newWidth = tileSize;
|
||||
}
|
||||
if (this.height < tileSize) {
|
||||
newHeight = tileSize;
|
||||
}
|
||||
if (newWidth === this.width && newHeight === this.height) {
|
||||
return;
|
||||
}
|
||||
const newData = new Uint8Array(newWidth * newHeight * 4);
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
const srcStart = y * this.width * 4;
|
||||
const destStart = y * newWidth * 4;
|
||||
newData.set(
|
||||
this.data.subarray(srcStart, srcStart + this.width * 4),
|
||||
destStart
|
||||
);
|
||||
}
|
||||
if (newWidth > this.width) {
|
||||
const rightColumnIndex = (this.width - 1) * 4;
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
const destRowStart = y * newWidth * 4;
|
||||
const srcPixelIndex = y * this.width * 4 + rightColumnIndex;
|
||||
const padPixel = this.data.subarray(srcPixelIndex, srcPixelIndex + 4);
|
||||
for (let x = this.width; x < newWidth; x++) {
|
||||
const destPixelIndex = destRowStart + x * 4;
|
||||
newData.set(padPixel, destPixelIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newHeight > this.height) {
|
||||
const bottomRowStart = (this.height - 1) * newWidth * 4;
|
||||
const bottomRow = newData.subarray(
|
||||
bottomRowStart,
|
||||
bottomRowStart + newWidth * 4
|
||||
);
|
||||
for (let y = this.height; y < newHeight; y++) {
|
||||
const destRowStart = y * newWidth * 4;
|
||||
newData.set(bottomRow, destRowStart);
|
||||
}
|
||||
}
|
||||
this.width = newWidth;
|
||||
this.height = newHeight;
|
||||
this.data = newData;
|
||||
}
|
||||
cropToOriginalSize(width: number, height: number) {
|
||||
const newData = new Uint8Array(width * height * 4);
|
||||
for (let y = 0; y < height; y++) {
|
||||
const srcStart = y * this.width * 4;
|
||||
const destStart = y * width * 4;
|
||||
newData.set(
|
||||
this.data.subarray(srcStart, srcStart + width * 4),
|
||||
destStart
|
||||
);
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,13 @@ self.addEventListener("message", async (e) => {
|
||||
return;
|
||||
}
|
||||
const input = new Img(data.width, data.height, new Uint8Array(data.input));
|
||||
const width_ori = input.width;
|
||||
const height_ori = input.height;
|
||||
input.padToTileSize(data?.tile_size || 64);
|
||||
let withPadding = false;
|
||||
if (input.width !== width_ori || input.height !== height_ori) {
|
||||
withPadding = true;
|
||||
}
|
||||
let hasAlpha = data.hasAlpha;
|
||||
function sendprogress(progress) {
|
||||
if (hasAlpha) {
|
||||
@@ -223,6 +230,9 @@ self.addEventListener("message", async (e) => {
|
||||
} catch (e) {
|
||||
postMessage({ alertmsg: e.toString() });
|
||||
}
|
||||
if (withPadding) {
|
||||
output.cropToOriginalSize(width_ori * factor, height_ori * factor);
|
||||
}
|
||||
const end = Date.now();
|
||||
console.log("Time:", end - start);
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
Reference in New Issue
Block a user