diff --git a/components.d.ts b/components.d.ts index ea5bc85..8f5e1b0 100644 --- a/components.d.ts +++ b/components.d.ts @@ -62,7 +62,6 @@ declare module 'vue' { CommentList: typeof import('./src/components/CommentReply/src/CommentList/CommentList.vue')['default'] CommentReply: typeof import('./src/components/CommentReply/index.vue')['default'] CompareImage: typeof import('./src/views/Upscale/CompareImage.vue')['default'] - CompareResult: typeof import('./src/views/Upscale/CompareResult.vue')['default'] Countdown: typeof import('./src/components/MyUI/Countdown/Countdown.vue')['default'] DatePicker: typeof import('./src/components/MyUI/DatePicker/DatePicker.vue')['default'] Descriptions: typeof import('./src/components/MyUI/Descriptions/Descriptions.vue')['default'] @@ -85,6 +84,7 @@ declare module 'vue' { LandingPage: typeof import('./src/views/Landing/LandingPage.vue')['default'] List: typeof import('./src/components/MyUI/List/List.vue')['default'] LoadingBar: typeof import('./src/components/MyUI/LoadingBar/LoadingBar.vue')['default'] + LoadingGraphic: typeof import('./src/components/LoadingGraphic/LoadingGraphic.vue')['default'] LocationAlbum: typeof import('./src/views/Album/LocationAlbum/LocationAlbum.vue')['default'] LockOutlined: typeof import('@ant-design/icons-vue')['LockOutlined'] LoginFooter: typeof import('./src/views/Login/LoginFooter.vue')['default'] @@ -97,11 +97,11 @@ declare module 'vue' { Notification: typeof import('./src/components/MyUI/Notification/Notification.vue')['default'] NumberAnimation: typeof import('./src/components/MyUI/NumberAnimation/NumberAnimation.vue')['default'] Pagination: typeof import('./src/components/MyUI/Pagination/Pagination.vue')['default'] + ParameterSetting: typeof import('./src/views/Upscale/ParameterSetting.vue')['default'] PeopleAlbum: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbum.vue')['default'] Phoalbum: typeof import('./src/views/Album/Phoalbum/Phoalbum.vue')['default'] Popconfirm: typeof import('./src/components/MyUI/Popconfirm/Popconfirm.vue')['default'] Popover: typeof import('./src/components/MyUI/Popover/Popover.vue')['default'] - ProcessResult: typeof import('./src/views/Upscale/ProcessResult.vue')['default'] Progress: typeof import('./src/components/MyUI/Progress/Progress.vue')['default'] QRCode: typeof import('./src/components/MyUI/QRCode/QRCode.vue')['default'] QRLogin: typeof import('./src/views/QRLogin/QRLogin.vue')['default'] @@ -134,7 +134,6 @@ declare module 'vue' { TabletOutlined: typeof import('@ant-design/icons-vue')['TabletOutlined'] Tabs: typeof import('./src/components/MyUI/Tabs/Tabs.vue')['default'] Tag: typeof import('./src/components/MyUI/Tag/Tag.vue')['default'] - TestCompare: typeof import('./src/views/Upscale/TestCompare.vue')['default'] Textarea: typeof import('./src/components/MyUI/Textarea/Textarea.vue')['default'] TextScroll: typeof import('./src/components/MyUI/TextScroll/TextScroll.vue')['default'] ThingAlbum: typeof import('./src/views/Album/ThingAlbum/ThingAlbum.vue')['default'] @@ -143,7 +142,7 @@ declare module 'vue' { TreeChart: typeof import('./src/components/MyUI/TreeChart/TreeChart.vue')['default'] Upload: typeof import('./src/components/MyUI/Upload/Upload.vue')['default'] UploadImage: typeof import('./src/views/Upscale/UploadImage.vue')['default'] - Upscale: typeof import('./src/views/Upscale/Upscale.vue')['default'] + Upscale: typeof import('./src/views/Upscale/index.vue')['default'] UserInfoCard: typeof import('./src/components/CommentReply/src/UserInfoCard/UserInfoCard.vue')['default'] UserOutlined: typeof import('@ant-design/icons-vue')['UserOutlined'] Video: typeof import('./src/components/MyUI/Video/Video.vue')['default'] diff --git a/package.json b/package.json index f8a7e0c..40e831b 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "buffer": "^6.0.3", "crypto-js": "^4.2.0", "echarts": "^5.5.1", - "eslint": "9.16.0", + "eslint": "9.17.0", "go-captcha-vue": "^2.0.5", "gsap": "^3.12.5", "jsencrypt": "^3.3.2", @@ -43,7 +43,7 @@ "nprogress": "^0.2.0", "nsfwjs": "^4.2.1", "pinia": "^2.3.0", - "pinia-plugin-persistedstate-2": "^2.0.27", + "pinia-plugin-persistedstate-2": "^2.0.28", "qrcode": "^1", "seedrandom": "^3.0.5", "swiper": "^11.1.15", @@ -58,17 +58,17 @@ "ws": "^8.18.0" }, "devDependencies": { - "@eslint/js": "^9.16.0", + "@eslint/js": "^9.17.0", "@vitejs/plugin-vue": "^5.2.1", "eslint-plugin-vue": "^9.32.0", "globals": "^15.13.0", "sass": "^1.83.0", - "typescript": "^5.7.2", + "typescript": "^5.6.3", "typescript-eslint": "^8.18.0", - "unplugin-vue-components": "^0.27.5", + "unplugin-vue-components": "^0.28.0", "vite": "^6.0.3", "vite-plugin-bundle-obfuscator": "1.4.0", "vite-plugin-chunk-split": "^0.5.0", - "vue-tsc": "https://pkg.pr.new/vuejs/language-tools/vue-tsc@3fb59af" + "vue-tsc": "2.1.10" } } diff --git a/src/assets/svgs/qr-phone.svg b/src/assets/svgs/qr-phone.svg index 35bd4a7..3319861 100644 --- a/src/assets/svgs/qr-phone.svg +++ b/src/assets/svgs/qr-phone.svg @@ -1 +1,11 @@ - + + + + + + diff --git a/src/assets/svgs/run.svg b/src/assets/svgs/run.svg index 85e0c57..9b04400 100644 --- a/src/assets/svgs/run.svg +++ b/src/assets/svgs/run.svg @@ -1 +1 @@ - + diff --git a/src/assets/svgs/success.svg b/src/assets/svgs/success.svg new file mode 100644 index 0000000..de2a3b9 --- /dev/null +++ b/src/assets/svgs/success.svg @@ -0,0 +1 @@ + diff --git a/src/assets/svgs/warn.svg b/src/assets/svgs/warn.svg new file mode 100644 index 0000000..6529cc7 --- /dev/null +++ b/src/assets/svgs/warn.svg @@ -0,0 +1 @@ + diff --git a/src/components/LoadingGraphic/LoadingGraphic.vue b/src/components/LoadingGraphic/LoadingGraphic.vue new file mode 100644 index 0000000..be5e37e --- /dev/null +++ b/src/components/LoadingGraphic/LoadingGraphic.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/components/MyUI/Modal/Modal.vue b/src/components/MyUI/Modal/Modal.vue index 66584c7..ae01733 100644 --- a/src/components/MyUI/Modal/Modal.vue +++ b/src/components/MyUI/Modal/Modal.vue @@ -599,7 +599,7 @@ defineExpose({ } .icon-info { - color: @themeColor; + color: #fff; } .icon-success { diff --git a/src/router/modules/main_router.ts b/src/router/modules/main_router.ts index ab3031b..a4ce84e 100644 --- a/src/router/modules/main_router.ts +++ b/src/router/modules/main_router.ts @@ -19,7 +19,7 @@ export default [ { path: '/main/photo/upscale', name: 'upscale', - component: () => import('@/views/Upscale/Upscale.vue'), + component: () => import('@/views/Upscale/index.vue'), meta: { requiresAuth: false, title: '图像修复' diff --git a/src/store/modules/upscaleStore.ts b/src/store/modules/upscaleStore.ts index 4beb57c..c5459f6 100644 --- a/src/store/modules/upscaleStore.ts +++ b/src/store/modules/upscaleStore.ts @@ -5,131 +5,120 @@ import i18n from "@/locales"; import {NSFWJS} from "nsfwjs"; import localForage from "localforage"; import {message} from "ant-design-vue"; -import Module from "@/workers/imghelper.ts"; import Img from "@/workers/image.ts"; +import Module from "@/workers/imghelper.ts"; export const useUpscaleStore = defineStore( 'upscale', () => { const image: HTMLImageElement = document.createElement('img'); - const imageList = ref([]); - const fileList = ref([]); + const imageData = ref(); + const fileData = ref(); const uploading = ref(false); // 加载图片数据 - const img = ref(new Image()); - const wasmModule = ref(); const hasAlpha = ref(false); const input = ref(null); const inputAlpha = ref(null); + const wasmModule = ref(null); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d', {willReadFrequently: true}); - const imgLoaded = ref(false); // 处理后的图片 - const processedImg = ref(new Image()); + const processedImg = ref(''); + const isDone = ref(false); + const isProcessing = ref(false); + const msg = ref(""); + const progressBar = ref(0); /** * 图片上传前的校验 * @param file */ - async function beforeUpload(file: any) { - if (fileList.value.length >= 5) { + async function beforeUpload(file: File) { + uploading.value = true; + const urlData = URL.createObjectURL(file); + image.src = urlData; + // 图片 NSFW 检测 + const nsfw: NSFWJS = await initNSFWJs(); + const isNSFW: boolean = await predictNSFW(nsfw, image); + if (isNSFW) { + message.error(i18n.global.t('comment.illegalImage')); + fileData.value = ''; + uploading.value = false; return false; } - uploading.value = true; - if (!window.FileReader) return false; - const reader = new FileReader(); - reader.readAsDataURL(file); // 文件转换 - reader.onload = async function () { - image.src = reader.result as string; - // 图片 NSFW 检测 - const nsfw: NSFWJS = await initNSFWJs(); - const isNSFW: boolean = await predictNSFW(nsfw, image); - if (isNSFW) { - message.error(i18n.global.t('comment.illegalImage')); - fileList.value.pop(); - uploading.value = false; - return false; - } - fileList.value.push(image.src); - // 加载图片 - await loadImg(image.src); - uploading.value = false; - return true; - }; + fileData.value = urlData; + await loadImg(image); + uploading.value = false; + + imageData.value = ""; + processedImg.value = ""; + isDone.value = false; + msg.value = ""; + progressBar.value = 0; + + return true; } /** * 自定义上传图片请求 */ - async function customUploadRequest() { - imageList.value = fileList.value; - } + async function customUploadRequest(_file: any) { - /** - * 移除图片 - * @param index - */ - async function removeImage(index: number) { - fileList.value.splice(index, 1); - imageList.value.splice(index, 1); + imageData.value = fileData.value; } /** * 加载图片 - * @param src + * @param img */ - async function loadImg(src: string) { - img.value.src = src; - img.value.onload = async () => { - wasmModule.value = await Module(); - if (ctx) { - canvas.width = img.value.width; - canvas.height = img.value.height; - ctx.drawImage(img.value, 0, 0); - const imageData = ctx.getImageData(0, 0, img.value.width, img.value.height); - const data = new Uint8Array(imageData.data.buffer); - input.value = new Img(img.value.width, img.value.height, data); - const numPixels = input.value.width * input.value.height; - const bytesPerImage = numPixels * 4; - const sourcePtr = wasmModule.value._malloc(bytesPerImage); - const targetPtr = wasmModule.value._malloc(bytesPerImage); - wasmModule.value.HEAPU8.set(input.value.data, sourcePtr); - hasAlpha.value = wasmModule.value._check_alpha(sourcePtr, numPixels); - if (hasAlpha.value) { - inputAlpha.value = new Img(img.value.width, img.value.height); - wasmModule.value._copy_alpha_to_rgb(sourcePtr, targetPtr, numPixels); - inputAlpha.value.data.set( - wasmModule.value.HEAPU8.subarray(targetPtr, targetPtr + bytesPerImage) - ); - } - wasmModule.value._free(sourcePtr); - wasmModule.value._free(targetPtr); - imgLoaded.value = true; + async function loadImg(img: HTMLImageElement) { + wasmModule.value = await Module(); + if (ctx && wasmModule.value) { + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + const imageData = ctx.getImageData(0, 0, img.width, img.height); + const data = new Uint8Array(imageData.data.buffer); + input.value = new Img(img.width, img.height, data); + const numPixels = input.value.width * input.value.height; + const bytesPerImage = numPixels * 4; + const sourcePtr = wasmModule.value._malloc(bytesPerImage); + const targetPtr = wasmModule.value._malloc(bytesPerImage); + wasmModule.value.HEAPU8.set(input.value.data, sourcePtr); + hasAlpha.value = wasmModule.value._check_alpha(sourcePtr, numPixels); + if (hasAlpha.value) { + inputAlpha.value = new Img(img.width, img.height); + wasmModule.value._copy_alpha_to_rgb(sourcePtr, targetPtr, numPixels); + inputAlpha.value.data.set( + wasmModule.value.HEAPU8.subarray(targetPtr, targetPtr + bytesPerImage) + ); } - }; + wasmModule.value._free(sourcePtr); + wasmModule.value._free(targetPtr); + } } return { - imageList, - fileList, uploading, + imageData, input, hasAlpha, inputAlpha, - wasmModule, - img, processedImg, - imgLoaded, + wasmModule, + isDone, + isProcessing, + msg, + progressBar, beforeUpload, customUploadRequest, - removeImage, }; } @@ -137,15 +126,10 @@ export const useUpscaleStore = defineStore( { // 开启数据持久化 persistedState: { - persist: true, + persist: false, storage: localForage, key: 'upscale', - includePaths: [ - 'imageList', - 'fileList', - 'img', - 'processedImg', - ] + includePaths: [], } } ) diff --git a/src/views/Photograph/AllPhoto/AllPhoto.vue b/src/views/Photograph/AllPhoto/AllPhoto.vue index 2448955..eb6d451 100644 --- a/src/views/Photograph/AllPhoto/AllPhoto.vue +++ b/src/views/Photograph/AllPhoto/AllPhoto.vue @@ -1,6 +1,5 @@ - - - diff --git a/src/views/RecyclingBin/RecyclingBin.vue b/src/views/RecyclingBin/RecyclingBin.vue index db3c841..633c11f 100644 --- a/src/views/RecyclingBin/RecyclingBin.vue +++ b/src/views/RecyclingBin/RecyclingBin.vue @@ -1,11 +1,8 @@ - - - + diff --git a/src/views/Upscale/CompareImage.vue b/src/views/Upscale/CompareImage.vue index 442addf..5dde30c 100644 --- a/src/views/Upscale/CompareImage.vue +++ b/src/views/Upscale/CompareImage.vue @@ -1,7 +1,7 @@ diff --git a/src/views/Upscale/ParameterSetting.vue b/src/views/Upscale/ParameterSetting.vue new file mode 100644 index 0000000..94ef92e --- /dev/null +++ b/src/views/Upscale/ParameterSetting.vue @@ -0,0 +1,298 @@ + + + diff --git a/src/views/Upscale/ProcessResult.vue b/src/views/Upscale/ProcessResult.vue deleted file mode 100644 index 47698d9..0000000 --- a/src/views/Upscale/ProcessResult.vue +++ /dev/null @@ -1,184 +0,0 @@ - - - diff --git a/src/views/Upscale/UploadImage.vue b/src/views/Upscale/UploadImage.vue index 2e5f21b..c2e95d1 100644 --- a/src/views/Upscale/UploadImage.vue +++ b/src/views/Upscale/UploadImage.vue @@ -1,106 +1,46 @@ @@ -122,44 +62,24 @@ onBeforeUnmount(() => { width: 100%; height: 100%; display: flex; - flex-direction: row; + flex-direction: column; align-items: center; + justify-content: space-around; overflow: scroll; - .upscale-upload-content-left { - width: 50%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-evenly; - .upscale-upload-text { - font-size: 20px; - font-weight: bold; - } - - .upscale-upload-btn { - width: 60%; - } - - .upscale-upload-tip { - font-size: 12px; - color: rgba(126, 126, 135, 0.99); - } + .upscale-upload-text { + font-size: 20px; + font-weight: bold; } - .upscale-upload-content-right { - width: 50%; - display: flex; - flex-direction: column; - align-items: center; - - .upscale-upload-qr-text { - font-size: 12px; - color: rgba(126, 126, 135, 0.99); - } + .upscale-upload-btn { + width: 60%; + } + .upscale-upload-tip { + font-size: 12px; + color: rgba(126, 126, 135, 0.99); } } } @@ -204,8 +124,5 @@ onBeforeUnmount(() => { align-items: center !important; justify-content: center !important; } - .upscale-upload-content-right { - display: none !important; - } } diff --git a/src/views/Upscale/Upscale.vue b/src/views/Upscale/Upscale.vue deleted file mode 100644 index 3d4c18b..0000000 --- a/src/views/Upscale/Upscale.vue +++ /dev/null @@ -1,388 +0,0 @@ - - - diff --git a/src/views/Upscale/index.vue b/src/views/Upscale/index.vue new file mode 100644 index 0000000..eb050d3 --- /dev/null +++ b/src/views/Upscale/index.vue @@ -0,0 +1,78 @@ + + +