chore: improve performance
parent
86a7033f3c
commit
23837b25ac
3
build.js
3
build.js
|
|
@ -27,8 +27,7 @@ async function build() {
|
||||||
bundle: true,
|
bundle: true,
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
outfile: 'dist/app.js',
|
outfile: 'dist/app.js',
|
||||||
loader: { '.png': 'file' },
|
loader: { '.png': 'dataurl' },
|
||||||
assetNames: 'assets/[name]',
|
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
minify: process.env.NODE_ENV === 'production'
|
minify: process.env.NODE_ENV === 'production'
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@
|
||||||
"build": "NODE_ENV=production node build.js",
|
"build": "NODE_ENV=production node build.js",
|
||||||
"serve": "npx serve dist"
|
"serve": "npx serve dist"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jszip": "^3.10.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.24.0"
|
"esbuild": "^0.24.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@ settings:
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
|
dependencies:
|
||||||
|
jszip:
|
||||||
|
specifier: ^3.10.1
|
||||||
|
version: 3.10.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.24.0
|
specifier: ^0.24.0
|
||||||
|
|
@ -164,11 +168,50 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
core-util-is@1.0.3:
|
||||||
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
|
|
||||||
esbuild@0.24.2:
|
esbuild@0.24.2:
|
||||||
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
|
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
immediate@3.0.6:
|
||||||
|
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||||
|
|
||||||
|
inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
|
isarray@1.0.0:
|
||||||
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
|
|
||||||
|
jszip@3.10.1:
|
||||||
|
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||||
|
|
||||||
|
lie@3.3.0:
|
||||||
|
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||||
|
|
||||||
|
pako@1.0.11:
|
||||||
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
|
||||||
|
process-nextick-args@2.0.1:
|
||||||
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
|
||||||
|
readable-stream@2.3.8:
|
||||||
|
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||||
|
|
||||||
|
safe-buffer@5.1.2:
|
||||||
|
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||||
|
|
||||||
|
setimmediate@1.0.5:
|
||||||
|
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||||
|
|
||||||
|
string_decoder@1.1.1:
|
||||||
|
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||||
|
|
||||||
|
util-deprecate@1.0.2:
|
||||||
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.24.2':
|
'@esbuild/aix-ppc64@0.24.2':
|
||||||
|
|
@ -246,6 +289,8 @@ snapshots:
|
||||||
'@esbuild/win32-x64@0.24.2':
|
'@esbuild/win32-x64@0.24.2':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
core-util-is@1.0.3: {}
|
||||||
|
|
||||||
esbuild@0.24.2:
|
esbuild@0.24.2:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.24.2
|
'@esbuild/aix-ppc64': 0.24.2
|
||||||
|
|
@ -273,3 +318,44 @@ snapshots:
|
||||||
'@esbuild/win32-arm64': 0.24.2
|
'@esbuild/win32-arm64': 0.24.2
|
||||||
'@esbuild/win32-ia32': 0.24.2
|
'@esbuild/win32-ia32': 0.24.2
|
||||||
'@esbuild/win32-x64': 0.24.2
|
'@esbuild/win32-x64': 0.24.2
|
||||||
|
|
||||||
|
immediate@3.0.6: {}
|
||||||
|
|
||||||
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
|
isarray@1.0.0: {}
|
||||||
|
|
||||||
|
jszip@3.10.1:
|
||||||
|
dependencies:
|
||||||
|
lie: 3.3.0
|
||||||
|
pako: 1.0.11
|
||||||
|
readable-stream: 2.3.8
|
||||||
|
setimmediate: 1.0.5
|
||||||
|
|
||||||
|
lie@3.3.0:
|
||||||
|
dependencies:
|
||||||
|
immediate: 3.0.6
|
||||||
|
|
||||||
|
pako@1.0.11: {}
|
||||||
|
|
||||||
|
process-nextick-args@2.0.1: {}
|
||||||
|
|
||||||
|
readable-stream@2.3.8:
|
||||||
|
dependencies:
|
||||||
|
core-util-is: 1.0.3
|
||||||
|
inherits: 2.0.4
|
||||||
|
isarray: 1.0.0
|
||||||
|
process-nextick-args: 2.0.1
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
string_decoder: 1.1.1
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
|
||||||
|
safe-buffer@5.1.2: {}
|
||||||
|
|
||||||
|
setimmediate@1.0.5: {}
|
||||||
|
|
||||||
|
string_decoder@1.1.1:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
|
||||||
|
util-deprecate@1.0.2: {}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,12 @@
|
||||||
|
|
||||||
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script src="https://unpkg.com/jszip@3.10.1/dist/jszip.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
tailwind.config = {
|
tailwind.config = {
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
primary: '#10B981', // 对应参考图的绿色
|
primary: '#10B981',
|
||||||
'primary-hover': '#059669',
|
'primary-hover': '#059669',
|
||||||
dark: '#1F2937',
|
dark: '#1F2937',
|
||||||
},
|
},
|
||||||
|
|
@ -32,12 +31,11 @@
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body { font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }
|
body { font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }
|
||||||
/* 自定义滚动条 */
|
|
||||||
::-webkit-scrollbar { width: 10px; }
|
::-webkit-scrollbar { width: 10px; }
|
||||||
::-webkit-scrollbar-track { background: #f1f1f1; }
|
::-webkit-scrollbar-track { background: #f1f1f1; }
|
||||||
::-webkit-scrollbar-thumb { background: #10B981; border-radius: 4px; }
|
::-webkit-scrollbar-thumb { background: #10B981; border-radius: 4px; }
|
||||||
|
|
||||||
/* 步骤条的箭头效果 */
|
|
||||||
.step-arrow::after {
|
.step-arrow::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -46,7 +44,7 @@
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
border-top: 15px solid transparent;
|
border-top: 15px solid transparent;
|
||||||
border-bottom: 15px solid transparent;
|
border-bottom: 15px solid transparent;
|
||||||
border-left: 15px solid #F3F4F6; /* gray-100 */
|
border-left: 15px solid #F3F4F6;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
|
@ -197,7 +195,7 @@
|
||||||
|
|
||||||
<section class="bg-gray-50 py-16 border-t border-gray-100">
|
<section class="bg-gray-50 py-16 border-t border-gray-100">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center md:mb-12">
|
<div class="text-center mb-6 md:mb-12">
|
||||||
<h3 class="text-2xl font-bold text-gray-900" data-i18n="feature.title">功能特点</h3>
|
<h3 class="text-2xl font-bold text-gray-900" data-i18n="feature.title">功能特点</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-8">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-8">
|
||||||
|
|
@ -241,8 +239,9 @@
|
||||||
<div>
|
<div>
|
||||||
<h6 class="font-bold mb-2 md:mb-4 text-emerald-100" data-i18n="footer.links">链接</h6>
|
<h6 class="font-bold mb-2 md:mb-4 text-emerald-100" data-i18n="footer.links">链接</h6>
|
||||||
<ul class="space-y-1 md:space-y-2 text-sm text-emerald-50">
|
<ul class="space-y-1 md:space-y-2 text-sm text-emerald-50">
|
||||||
<li><a href="./terms.html" class="hover:text-white" data-i18n="footer.terms">使用条款</a></li>
|
<li><a href="/terms.html" class="hover:text-white" data-i18n="footer.terms">使用条款</a></li>
|
||||||
<li><a href="https://github.com/journey-ad/gemini-watermark-web" target="_blank" class="hover:text-white">Github</a></li>
|
<li><a href="https://github.com/journey-ad/gemini-watermark-web" target="_blank" class="hover:text-white">Github</a></li>
|
||||||
|
<li><a href="/userscript/gemini-watermark-remover.user.js" target="_blank" class="hover:text-white" data-i18n="nav.userscript">油猴脚本</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -265,7 +264,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/i18n.js"></script>
|
<script src="app.js"></script>
|
||||||
<script src="/app.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
17
src/app.js
17
src/app.js
|
|
@ -1,16 +1,13 @@
|
||||||
/**
|
|
||||||
* 主应用程序 - UI 交互逻辑
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { WatermarkEngine } from './core/watermarkEngine.js';
|
import { WatermarkEngine } from './core/watermarkEngine.js';
|
||||||
import i18n from './i18n.js';
|
import i18n from './i18n.js';
|
||||||
|
import JSZip from 'jszip';
|
||||||
|
|
||||||
// 全局状态
|
// global state
|
||||||
let engine = null;
|
let engine = null;
|
||||||
let imageQueue = [];
|
let imageQueue = [];
|
||||||
let processedCount = 0;
|
let processedCount = 0;
|
||||||
|
|
||||||
// DOM 元素
|
// dom elements references
|
||||||
const uploadArea = document.getElementById('uploadArea');
|
const uploadArea = document.getElementById('uploadArea');
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
const singlePreview = document.getElementById('singlePreview');
|
const singlePreview = document.getElementById('singlePreview');
|
||||||
|
|
@ -29,7 +26,7 @@ const resetBtn = document.getElementById('resetBtn');
|
||||||
const statusMessage = document.getElementById('statusMessage');
|
const statusMessage = document.getElementById('statusMessage');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化应用
|
* initialize the application
|
||||||
*/
|
*/
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -48,7 +45,7 @@ async function init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置语言切换
|
* setup language switch
|
||||||
*/
|
*/
|
||||||
function setupLanguageSwitch() {
|
function setupLanguageSwitch() {
|
||||||
const btn = document.getElementById('langSwitch');
|
const btn = document.getElementById('langSwitch');
|
||||||
|
|
@ -62,7 +59,7 @@ function setupLanguageSwitch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置事件监听器
|
* setup event listeners
|
||||||
*/
|
*/
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
uploadArea.addEventListener('click', () => fileInput.click());
|
uploadArea.addEventListener('click', () => fileInput.click());
|
||||||
|
|
@ -143,7 +140,7 @@ async function processSingle(item) {
|
||||||
originalCanvas.height = img.height;
|
originalCanvas.height = img.height;
|
||||||
originalCanvas.getContext('2d').drawImage(img, 0, 0);
|
originalCanvas.getContext('2d').drawImage(img, 0, 0);
|
||||||
|
|
||||||
// 显示图片信息
|
// update original image info
|
||||||
const watermarkInfo = engine.getWatermarkInfo(img.width, img.height);
|
const watermarkInfo = engine.getWatermarkInfo(img.width, img.height);
|
||||||
originalInfo.innerHTML = `
|
originalInfo.innerHTML = `
|
||||||
<strong>${i18n.t('info.size')}:</strong>${img.width} × ${img.height} px<br>
|
<strong>${i18n.t('info.size')}:</strong>${img.width} × ${img.height} px<br>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"title": "Gemini Watermark Remover - Lossless Watermark Removal Tool",
|
"title": "Gemini Watermark Remover - Lossless Watermark Removal Tool",
|
||||||
"header.title": "Gemini Watermark Remover",
|
"header.title": "Gemini Watermark Remover",
|
||||||
"nav.userscript": "Userscript for Gemini",
|
"nav.userscript": "Install Userscript for Gemini",
|
||||||
"nav.principle": "How It Works?",
|
"nav.principle": "How It Works?",
|
||||||
"main.title": "Gemini AI Watermark Removal",
|
"main.title": "Gemini AI Watermark Removal",
|
||||||
"main.subtitle": "Based on reverse alpha blending algorithm, pure browser-side processing, Free, Fast, and Lossless",
|
"main.subtitle": "Based on reverse alpha blending algorithm, pure browser-side processing, Free, Fast, and Lossless",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"title": "Gemini Watermark Remover - Gemini 无损去水印工具",
|
"title": "Gemini Watermark Remover - Gemini 无损去水印工具",
|
||||||
"header.title": "Gemini Watermark Remover",
|
"header.title": "Gemini Watermark Remover",
|
||||||
"nav.userscript": "油猴脚本",
|
"nav.userscript": "安装油猴脚本",
|
||||||
"nav.principle": "去水印原理",
|
"nav.principle": "去水印原理",
|
||||||
"main.title": "Gemini AI 图像去水印",
|
"main.title": "Gemini AI 图像去水印",
|
||||||
"main.subtitle": "基于反向 Alpha 混合算法,纯浏览器本地处理,免费、极速、无损",
|
"main.subtitle": "基于反向 Alpha 混合算法,纯浏览器本地处理,免费、极速、无损",
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
"feature.speed.title": "极速处理",
|
"feature.speed.title": "极速处理",
|
||||||
"feature.speed.desc": "基于现代浏览器技术加速处理,毫秒级响应,无需等待排队",
|
"feature.speed.desc": "基于现代浏览器技术加速处理,毫秒级响应,无需等待排队",
|
||||||
"feature.privacy.title": "隐私安全",
|
"feature.privacy.title": "隐私安全",
|
||||||
"feature.privacy.desc": "纯前端运行,图片数据不离机,绝不上传服务器",
|
"feature.privacy.desc": "浏览器前端本地运行,图片数据不会离开您的设备,绝不会上传服务器",
|
||||||
"feature.free.title": "完全免费",
|
"feature.free.title": "完全免费",
|
||||||
"feature.free.desc": "无次数限制,无隐藏付费,即开即用",
|
"feature.free.desc": "无次数限制,无隐藏付费,即开即用",
|
||||||
"footer.desc": "Gemini 无损去水印工具,本工具仅供学习交流使用",
|
"footer.desc": "Gemini 无损去水印工具,本工具仅供学习交流使用",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue