🚸 optimize

This commit is contained in:
2024-12-20 01:23:51 +08:00
parent 8ab873f5ce
commit 76336d1553
19 changed files with 276 additions and 161 deletions

View File

@@ -8,11 +8,9 @@ export const generateClientId = () => {
{ {
meta: { meta: {
ignoreToken: true, ignoreToken: true,
signature: true
}, },
cacheFor: { cacheFor: null,
mode: "restore",
expire: 1000 * 60 * 60 * 24
}
} }
); );
}; };

View File

@@ -58,7 +58,7 @@ export const commentListApi = (params: any) => {
}, },
{ {
cacheFor: { cacheFor: {
expire: 60 * 60 * 24 * 7, expire: 60 * 60 * 24,
mode: "restore", mode: "restore",
}, // 7天缓存 }, // 7天缓存
hitSource: "comment-submit", hitSource: "comment-submit",
@@ -81,7 +81,7 @@ export const replyListApi = (params: any) => {
}, },
{ {
cacheFor: { cacheFor: {
expire: 60 * 60 * 24 * 7, expire: 60 * 60 * 24,
mode: "restore", mode: "restore",
}, // 7天缓存 }, // 7天缓存
hitSource: ["reply-submit", "reply-reply-submit"], hitSource: ["reply-submit", "reply-reply-submit"],

View File

@@ -11,7 +11,7 @@ export const getGiteeUrl = () => {
}, },
cacheFor: { cacheFor: {
mode: "restore", mode: "restore",
expire: 1000 * 60 * 60 * 24 * 7 expire: 1000 * 60 * 60 * 24
} }
} }
); );

View File

@@ -14,7 +14,7 @@ export const getGithubUrl = (state: string) => {
}, },
cacheFor: { cacheFor: {
mode: "restore", mode: "restore",
expire: 1000 * 60 * 60 * 24 * 7 expire: 1000 * 60 * 60 * 24
} }
} }
); );

View File

@@ -11,7 +11,7 @@ export const getQQUrl = (state: string) => {
}, },
cacheFor: { cacheFor: {
mode: "restore", mode: "restore",
expire: 1000 * 60 * 60 * 24 * 7 expire: 1000 * 60 * 60 * 24
} }
} }
); );

View File

@@ -10,7 +10,7 @@ export const generateQrCode = (clientId: string) => {
params: { params: {
client_id: clientId client_id: clientId
}, },
cacheFor: 1000 * 60 * 60 * 24 * 7, cacheFor: null,
meta: { meta: {
ignoreToken: true, ignoreToken: true,
}, },

View File

@@ -8,7 +8,7 @@ export const refreshToken = () => {
return service.Post('/api/auth/token/refresh', {}, { return service.Post('/api/auth/token/refresh', {}, {
meta: { meta: {
authRole: 'refreshToken', authRole: 'refreshToken',
ignoreToken: false, ignoreToken: true,
signature: true signature: true
} }
}); });
@@ -93,11 +93,14 @@ export const resetPasswordApi = (param: ResetPassword) => {
/** /**
* 获取用户设备信息 * 获取用户设备信息
* @param access_token
*/ */
export const getUserDevice = () => { export const getUserDevice = (access_token: string) => {
return service.Get('/api/user/device', return service.Post('/api/user/device',
{
access_token: access_token,
},
{ {
params: {},
meta: { meta: {
ignoreToken: true, ignoreToken: true,
signature: true signature: true

View File

@@ -12,6 +12,73 @@ import Module from "@/workers/imghelper.ts";
export const useUpscaleStore = defineStore( export const useUpscaleStore = defineStore(
'upscale', 'upscale',
() => { () => {
// 模型参数
const TypeData = ref<string[]>(['realesrgan', 'realcugan']);
const model_type = ref<string>(TypeData.value[0]);
const ModelConfig = reactive({
realesrgan: {
model: ["anime_fast", "anime_plus", "general_fast", "general_plus"],
factor: [4],
tile_size: [32, 48, 64, 96, 128, 192, 256],
},
realcugan: {
factor: [2, 4],
denoise: {
2: [
"conservative",
"no-denoise",
"denoise1x",
"denoise2x",
"denoise3x",
],
3: ["conservative", "denoise3x"],
4: ["conservative", "no-denoise", "denoise3x"],
},
tile_size: [32, 48, 64, 96, 128, 192, 256, 384, 512],
}
});
const factor = ref<number>(4);
const model = ref(ModelConfig[model_type.value].model[0]);
const modes = computed(() => {
if (model_type.value === "realesrgan") {
return ModelConfig[model_type.value].model;
} else {
return ModelConfig[model_type.value].denoise[factor.value];
}
});
watch(model_type, val => {
if (model_type.value === "realesrgan") {
model.value = ModelConfig[val].model[0];
} else {
model.value = ModelConfig[val].denoise[factor.value][0];
}
});
// Scale
const scales = computed(() => {
return ModelConfig[model_type.value].factor;
});
//tile size
const tile_size = ref<number>(128);
const tileSize = computed(() => {
return ModelConfig[model_type.value].tile_size;
});
// overlap
const overlapList = ref<number[]>([0, 4, 8, 12, 16, 20]);
const min_lap = ref<number>(overlapList.value[3]);
// run on
const backendList = ref<string[]>(['webgl', 'webgpu']);
const backend = ref<string>(backendList.value[0]);
// ***************图片处理***************
const image: HTMLImageElement = document.createElement('img'); const image: HTMLImageElement = document.createElement('img');
const imageData = ref<string>(); const imageData = ref<string>();
const fileData = ref<string>(); const fileData = ref<string>();
@@ -33,7 +100,7 @@ export const useUpscaleStore = defineStore(
const isProcessing = ref<boolean>(false); const isProcessing = ref<boolean>(false);
const msg = ref<string>(""); const msg = ref<string>("");
const progressBar = ref<number>(0); const progressBar = ref<number>(0);
const status = ref<string>('loading');
/** /**
* 图片上传前的校验 * 图片上传前的校验
* @param file * @param file
@@ -111,6 +178,19 @@ export const useUpscaleStore = defineStore(
return { return {
TypeData,
model_type,
ModelConfig,
model,
modes,
factor,
tile_size,
tileSize,
scales,
overlapList,
min_lap,
backend,
backendList,
uploading, uploading,
imageData, imageData,
input, input,
@@ -122,6 +202,7 @@ export const useUpscaleStore = defineStore(
isProcessing, isProcessing,
msg, msg,
progressBar, progressBar,
status,
loadImg, loadImg,
beforeUpload, beforeUpload,
customUploadRequest, customUploadRequest,

View File

@@ -5,7 +5,7 @@ import {getGithubUrl} from "@/api/oauth/github.ts";
import {getQQUrl} from "@/api/oauth/qq.ts"; import {getQQUrl} from "@/api/oauth/qq.ts";
import {getGiteeUrl} from "@/api/oauth/gitee.ts"; import {getGiteeUrl} from "@/api/oauth/gitee.ts";
import {getUserDevice} from "@/api/user"; import {getUserDevice} from "@/api/user";
import message from "@/components/MyUI/Message/Message.vue"; import {message} from "ant-design-vue";
import {useI18n} from "vue-i18n"; import {useI18n} from "vue-i18n";
export const useAuthStore = defineStore( export const useAuthStore = defineStore(
@@ -70,17 +70,18 @@ export const useAuthStore = defineStore(
* 处理消息 * 处理消息
* @param e * @param e
*/ */
const messageHandler = async (e: any) => { const messageHandler = async (e: MessageEvent) => {
if (typeof e.data === 'string') { if (typeof e.data === 'string') {
const res: any = JSON.parse(e.data); const res: any = JSON.parse(e.data);
if (res && res.code === 200) { if (res && res.code === 200) {
user.uid = res.data.uid; const {data} = res;
user.access_token = res.data.access_token; user.uid = data.uid;
user.username = res.data.username; user.access_token = data.access_token;
user.avatar = res.data.avatar; user.username = data.username;
user.nickname = res.data.nickname; user.avatar = data.avatar;
user.status = res.data.status; user.nickname = data.nickname;
await getUserDevice(); user.status = data.status;
await getUserDevice(data.access_token);
message.success(t('login.loginSuccess')); message.success(t('login.loginSuccess'));
window.removeEventListener("message", messageHandler); window.removeEventListener("message", messageHandler);
setTimeout(() => { setTimeout(() => {

View File

@@ -20,7 +20,13 @@ export const useWebSocketStore = defineStore('websocket', () => {
}) { }) {
state.wsService = new WebSocketService(options); state.wsService = new WebSocketService(options);
state.wsService?.open(); state.wsService?.open();
state.wsService?.on('open', () => {
readyState.value = WebSocket.OPEN; readyState.value = WebSocket.OPEN;
});
state.wsService?.on('close', () => {
readyState.value = WebSocket.CLOSED;
});
} }
function sendMessage(data: any) { function sendMessage(data: any) {

View File

@@ -41,7 +41,7 @@ export const service = createAlova({
requestAdapter: axiosRequestAdapter(), requestAdapter: axiosRequestAdapter(),
l2Cache: localforageStorageAdapter, l2Cache: localforageStorageAdapter,
cacheLogger: import.meta.env.VITE_NODE_ENV === 'development', cacheLogger: import.meta.env.VITE_NODE_ENV === 'development',
cacheFor: {}, cacheFor: null,
// 设置全局的请求拦截器 // 设置全局的请求拦截器
beforeRequest: onAuthRequired(async (method: any) => { beforeRequest: onAuthRequired(async (method: any) => {
if (!method.meta?.ignoreToken) { if (!method.meta?.ignoreToken) {

View File

@@ -6,7 +6,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.400"), content: i18n.global.t("error.400"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -15,7 +15,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.401"), content: i18n.global.t("error.401"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -24,7 +24,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.403"), content: i18n.global.t("error.403"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -33,7 +33,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.404"), content: i18n.global.t("error.404"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -42,7 +42,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.408"), content: i18n.global.t("error.408"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -51,7 +51,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.500"), content: i18n.global.t("error.500"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -60,7 +60,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.501"), content: i18n.global.t("error.501"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -69,7 +69,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.502"), content: i18n.global.t("error.502"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -78,7 +78,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.503"), content: i18n.global.t("error.503"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -87,7 +87,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.504"), content: i18n.global.t("error.504"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -96,7 +96,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.505"), content: i18n.global.t("error.505"),
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();
@@ -105,7 +105,7 @@ export function handleErrorCode(code: number): void {
message message
.open({ .open({
content: i18n.global.t("error.other") + `(${code})`, content: i18n.global.t("error.other") + `(${code})`,
duration: 5, duration: 3,
type: "error", type: "error",
}) })
.then(); .then();

View File

@@ -0,0 +1,29 @@
async function getImageSizeWithUnit(url: string): Promise<string> {
let sizeInBytes: number;
// 处理 base64 格式的图片 URL
if (url.startsWith('data:')) {
sizeInBytes = atob(url.split(',')[1]).length * 0.75;
}
// 处理 blob 格式的图片 URL
else if (url.startsWith('blob:')) {
const response = await fetch(url);
const blob = await response.blob();
sizeInBytes = blob.size;
} else {
throw new Error('Unsupported URL format');
}
let unit = 'Bytes';
if (sizeInBytes >= 1024 * 1024) {
sizeInBytes /= (1024 * 1024);
unit = 'MB';
} else if (sizeInBytes >= 1024) {
sizeInBytes /= 1024;
unit = 'KB';
}
return `${parseFloat(sizeInBytes.toFixed(2))} ${unit}`;
}
export default getImageSizeWithUnit;

View File

@@ -53,7 +53,7 @@ export class WebSocketService {
}; };
private handleMessage = (event: MessageEvent): void => { private handleMessage = (event: MessageEvent): void => {
const data = JSON.parse(event.data); const {data} = event;
if (this.callbacks.message) { if (this.callbacks.message) {
this.callbacks.message.forEach((cb) => (cb as MessageCallback)(data)); this.callbacks.message.forEach((cb) => (cb as MessageCallback)(data));
} }
@@ -71,9 +71,6 @@ export class WebSocketService {
console.log('WebSocket连接已关闭'); console.log('WebSocket连接已关闭');
if (this.callbacks.close) { if (this.callbacks.close) {
this.callbacks.close.forEach((cb) => (cb as EventCallback)()); this.callbacks.close.forEach((cb) => (cb as EventCallback)());
if (!this.options.reconnectTimeout) {
this.reconnect();
}
} }
}; };
@@ -84,8 +81,4 @@ export class WebSocketService {
console.warn('尝试发送消息时WebSocket未连接'); console.warn('尝试发送消息时WebSocket未连接');
} }
} }
public getReadyState(): number {
return this.ws ? this.ws.readyState : WebSocket.CLOSED;
}
} }

View File

@@ -47,7 +47,6 @@ import BoxDog from "@/components/BoxDog/BoxDog.vue";
import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue"; import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue";
import {useRouter} from 'vue-router'; import {useRouter} from 'vue-router';
import {generateQrCode} from "@/api/oauth/wechat.ts"; import {generateQrCode} from "@/api/oauth/wechat.ts";
import {onBeforeUnmount, onMounted, ref} from "vue";
import logo from "@/assets/svgs/logo-album.svg"; import logo from "@/assets/svgs/logo-album.svg";
import useStore from "@/store"; import useStore from "@/store";
@@ -71,7 +70,6 @@ const userStore = useStore().user;
async function getQrCode() { async function getQrCode() {
const res: any = await generateQrCode(userStore.clientId); const res: any = await generateQrCode(userStore.clientId);
if (res && res.code === 200) { if (res && res.code === 200) {
status.value = 'active';
qrcode.value = res.data; qrcode.value = res.data;
await handleListenMessage(); await handleListenMessage();
} else { } else {
@@ -82,6 +80,7 @@ async function getQrCode() {
const wsOptions = { const wsOptions = {
url: import.meta.env.VITE_QR_SOCKET_URL + "?client_id=" + userStore.clientId, url: import.meta.env.VITE_QR_SOCKET_URL + "?client_id=" + userStore.clientId,
reconnectTimeout: 10000,
}; };
@@ -93,14 +92,15 @@ async function handleListenMessage() {
// 注册消息接收处理函数 // 注册消息接收处理函数
websocket.on('message', async (res: any) => { websocket.on('message', async (res: any) => {
if (res && res.code === 200) { if (res && res.code === 200) {
userStore.user.uid = res.data.uid;
userStore.user.access_token = res.data.access_token;
userStore.user.username = res.data.username;
userStore.user.avatar = res.data.avatar;
userStore.user.nickname = res.data.nickname;
userStore.user.status = res.data.status;
status.value = 'scanned'; status.value = 'scanned';
await getUserDevice(); const {data} = res;
userStore.user.uid = data.uid;
userStore.user.access_token = data.access_token;
userStore.user.username = data.username;
userStore.user.avatar = data.avatar;
userStore.user.nickname = data.nickname;
userStore.user.status = data.status;
await getUserDevice(data.access_token);
message.success(t('login.loginSuccess')); message.success(t('login.loginSuccess'));
setTimeout(() => { setTimeout(() => {
router.push('/main/photo/all'); router.push('/main/photo/all');
@@ -117,6 +117,17 @@ onMounted(async () => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
websocket.close(false); websocket.close(false);
}); });
watch(
() => websocket.readyState,
(newStatus) => {
if (newStatus === WebSocket.OPEN) {
status.value = 'active';
} else {
status.value = 'expired';
}
}
);
</script> </script>
<style src="./index.scss" lang="scss" scoped> <style src="./index.scss" lang="scss" scoped>

View File

@@ -1,7 +1,11 @@
<template> <template>
<div <div
ref="canvasContainer" ref="canvasContainer"
class="canvas-container bg drag-over dark" class="canvas-container bg"
:class="{
'drag-over':false,
'dark':false
}"
@mousedown="startDragging" @mousedown="startDragging"
@mouseup="stopDragging" @mouseup="stopDragging"
@mouseleave="stopDragging" @mouseleave="stopDragging"
@@ -51,6 +55,8 @@
:value="generateQrCodeUrl()" :value="generateQrCodeUrl()"
:icon="phone" :icon="phone"
:iconSize="iconSize" :iconSize="iconSize"
:status="store.status"
/> />
<span class="canvas-qr-text">手机扫码上传</span> <span class="canvas-qr-text">手机扫码上传</span>
</div> </div>
@@ -87,6 +93,11 @@
</ATooltip> </ATooltip>
</AFlex> </AFlex>
</div> </div>
<!-- 图片信息 -->
<div class="image-info">
<ATag color="cyan" :bordered="false" v-if="store.imageData">修复前: {{ originalImageSize }}</ATag>
<ATag color="purple" :bordered="false" v-if="store.processedImg">修复后: {{ processedImageSize }}</ATag>
</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -96,6 +107,7 @@ import download from '@/assets/svgs/download.svg';
import share from '@/assets/svgs/share.svg'; import share from '@/assets/svgs/share.svg';
import save from '@/assets/svgs/save.svg'; import save from '@/assets/svgs/save.svg';
import deleted from '@/assets/svgs/deleted.svg'; import deleted from '@/assets/svgs/deleted.svg';
import getImageSizeWithUnit from "@/utils/imageUtils/getImageSizeWithUnit.ts";
const canvasContainer = ref<HTMLDivElement | null>(null); const canvasContainer = ref<HTMLDivElement | null>(null);
const dragging = ref<boolean>(false); const dragging = ref<boolean>(false);
@@ -124,6 +136,11 @@ const processedImg = ref<HTMLImageElement>(new Image());
const qrcodeSize = ref<number>(250); const qrcodeSize = ref<number>(250);
const iconSize = ref<number>(30); const iconSize = ref<number>(30);
const originalImageSize = ref<string>('');
const processedImageSize = ref<string>('');
/** /**
* 更新二维码大小 * 更新二维码大小
*/ */
@@ -140,8 +157,6 @@ function generateQrCodeUrl(): string {
return import.meta.env.VITE_APP_WEB_URL + "/upscale/app?user_id=" + user.user.uid + "&token=" + user.user.access_token; return import.meta.env.VITE_APP_WEB_URL + "/upscale/app?user_id=" + user.user.uid + "&token=" + user.user.access_token;
} }
console.log(generateQrCodeUrl());
/** /**
* 下载图片 * 下载图片
*/ */
@@ -149,8 +164,22 @@ function downloadImage() {
if (!store.processedImg) return; if (!store.processedImg) return;
const a = document.createElement("a"); const a = document.createElement("a");
a.href = store.processedImg; a.href = store.processedImg;
if (store.hasAlpha) a.download = "output.png"; if (store.hasAlpha) a.download = store.model_type +
else a.download = "output.jpg"; "_" + store.model +
"_" + store.factor +
"_" + store.tile_size +
"_" + store.min_lap +
"_" + store.backend +
"_" +
"output.png";
else a.download = store.model_type +
"_" + store.model +
"_" + store.factor +
"_" + store.tile_size +
"_" + store.min_lap +
"_" + store.backend +
"_" +
"output.jpg";
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
@@ -529,8 +558,9 @@ watch(
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {
img.value.src = newValue; img.value.src = newValue;
img.value.onload = () => { img.value.onload = async () => {
initCanvasSize(); initCanvasSize();
originalImageSize.value = await getImageSizeWithUnit(newValue);
}; };
} }
} }
@@ -540,8 +570,9 @@ watch(
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {
processedImg.value.src = newValue; processedImg.value.src = newValue;
processedImg.value.onload = () => { processedImg.value.onload = async () => {
initCanvasSize(); initCanvasSize();
processedImageSize.value = await getImageSizeWithUnit(newValue);
}; };
} }
} }
@@ -567,6 +598,8 @@ onBeforeUnmount(() => {
height: 100%; height: 100%;
position: relative; position: relative;
z-index: 0; z-index: 0;
border-radius: 10px;
overflow: hidden;
} }
.bg { .bg {
@@ -640,6 +673,7 @@ canvas {
height: 100%; height: 100%;
width: 100%; width: 100%;
z-index: 2; z-index: 2;
border-radius: 10px;
} }
.canvas-qr { .canvas-qr {
@@ -708,7 +742,7 @@ canvas {
.canvas-progressbar-text { .canvas-progressbar-text {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
color: white; color: #000000;
} }
.floating-menu { .floating-menu {
@@ -747,4 +781,22 @@ canvas {
.menu-icon:hover { .menu-icon:hover {
transform: scale(1.1); transform: scale(1.1);
} }
.image-info {
position: absolute;
opacity: 0.8;
border-radius: 10px;
top: 0;
right: 0;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 10px;
align-items: flex-start;
transition: all 0.5s ease;
user-select: none;
z-index: 3;
}
</style> </style>

View File

@@ -4,15 +4,15 @@
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">类型:</span> <span class="upscale-params-title">类型:</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="model_type" v-model:value="upscale.model_type"
:options="TypeData.map(item => ({label: item, value: item}))"> :options="upscale.TypeData.map(item => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">模型:</span> <span class="upscale-params-title">模型:</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="model" v-model:value="upscale.model"
:options="modes.map((item: any) => ({label: item, value: item}))"> :options="upscale.modes.map((item: any) => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
</div> </div>
@@ -20,16 +20,16 @@
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">比列:</span> <span class="upscale-params-title">比列:</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="factor" v-model:value="upscale.factor"
:options="scales.map((item: any) => ({label: item, value: item}))"> :options="upscale.scales.map((item: any) => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">分块大小:</span> <span class="upscale-params-title">分块大小:</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="tile_size" v-model:value="upscale.tile_size"
:options="tileSize.map((item: any) => ({label: item, value: item}))"> :options="upscale.tileSize.map((item: any) => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
@@ -38,15 +38,15 @@
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">重复:</span> <span class="upscale-params-title">重复:</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="min_lap" v-model:value="upscale.min_lap"
:options="overlapList.map((item: any) => ({label: item, value: item}))"> :options="upscale.overlapList.map((item: any) => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
<div class="upscale-params-item-content"> <div class="upscale-params-item-content">
<span class="upscale-params-title">运行环境</span> <span class="upscale-params-title">运行环境</span>
<ASelect style="width: 100%" size="large" <ASelect style="width: 100%" size="large"
v-model:value="backend" v-model:value="upscale.backend"
:options="backendList.map((item: any) => ({label: item, value: item}))"> :options="upscale.backendList.map((item: any) => ({label: item, value: item}))">
</ASelect> </ASelect>
</div> </div>
</div> </div>
@@ -69,70 +69,6 @@ import useStore from "@/store";
import run from '@/assets/svgs/run.svg'; import run from '@/assets/svgs/run.svg';
const upscale = useStore().upscale; const upscale = useStore().upscale;
// ***************参数设置***************
const TypeData = ['realesrgan', 'realcugan'];
const model_type = ref<string>(TypeData[0]);
const ModelConfig = reactive({
realesrgan: {
model: ["anime_fast", "anime_plus", "general_fast", "general_plus"],
factor: [4],
tile_size: [32, 48, 64, 96, 128, 192, 256],
},
realcugan: {
factor: [2, 4],
denoise: {
2: [
"conservative",
"no-denoise",
"denoise1x",
"denoise2x",
"denoise3x",
],
3: ["conservative", "denoise3x"],
4: ["conservative", "no-denoise", "denoise3x"],
},
tile_size: [32, 48, 64, 96, 128, 192, 256, 384, 512],
}
});
const factor = ref<number>(4);
const model = ref(ModelConfig[model_type.value].model[0]);
const modes = computed(() => {
if (model_type.value === "realesrgan") {
return ModelConfig[model_type.value].model;
} else {
return ModelConfig[model_type.value].denoise[factor.value];
}
});
watch(model_type, val => {
if (model_type.value === "realesrgan") {
model.value = ModelConfig[val].model[0];
} else {
model.value = ModelConfig[val].denoise[factor.value][0];
}
});
// Scale
const scales = computed(() => {
return ModelConfig[model_type.value].factor;
});
//tile size
const tile_size = ref<number>(128);
const tileSize = computed(() => {
return ModelConfig[model_type.value].tile_size;
});
// overlap
const overlapList = [0, 4, 8, 12, 16, 20];
const min_lap = ref<number>(overlapList[3]);
// run on
const backendList = ['webgl', 'webgpu'];
const backend = ref<string>(backendList[0]);
// ********************处理图片******************* // ********************处理图片*******************
const outputData = ref<any>(); const outputData = ref<any>();
@@ -166,8 +102,8 @@ async function startTask() {
if (!upscale.hasAlpha || (upscale.hasAlpha && upscale.inputAlpha)) { if (!upscale.hasAlpha || (upscale.hasAlpha && upscale.inputAlpha)) {
if (upscale.input) { if (upscale.input) {
outputData.value = new Img( outputData.value = new Img(
factor.value * upscale.input.width, upscale.factor * upscale.input.width,
factor.value * upscale.input.height, upscale.factor * upscale.input.height,
new Uint8Array(output) new Uint8Array(output)
); );
} }
@@ -177,14 +113,14 @@ async function startTask() {
worker.postMessage( worker.postMessage(
{ {
input: upscale.inputAlpha.data.buffer, input: upscale.inputAlpha.data.buffer,
factor: factor.value, factor: upscale.factor,
tile_size: tile_size.value, tile_size: upscale.tile_size,
min_lap: min_lap.value, min_lap: upscale.min_lap,
model_type: model_type.value, model_type: upscale.model_type,
width: upscale.inputAlpha.width, width: upscale.inputAlpha.width,
height: upscale.inputAlpha.height, height: upscale.inputAlpha.height,
model: model.value, model: upscale.model,
backend: backend.value, backend: upscale.backend,
hasAlpha: true, hasAlpha: true,
}, },
[upscale.inputAlpha.data.buffer] [upscale.inputAlpha.data.buffer]
@@ -247,14 +183,14 @@ async function startTask() {
worker.postMessage( worker.postMessage(
{ {
input: upscale.input.data.buffer, input: upscale.input.data.buffer,
factor: factor.value, factor: upscale.factor,
tile_size: tile_size.value, tile_size: upscale.tile_size,
min_lap: min_lap.value, min_lap: upscale.min_lap,
model_type: model_type.value, model_type: upscale.model_type,
width: upscale.input.width, width: upscale.input.width,
height: upscale.input.height, height: upscale.input.height,
model: model.value, model: upscale.model,
backend: backend.value, backend: upscale.backend,
hasAlpha: false, hasAlpha: false,
}, },
[upscale.input.data.buffer] [upscale.input.data.buffer]

View File

@@ -13,7 +13,7 @@
</ACard> </ACard>
</div> </div>
<div class="upscale-content-right"> <div class="upscale-content-right">
<CompareImage style="border-radius: 10px"/> <CompareImage/>
</div> </div>
</AFlex> </AFlex>
</div> </div>
@@ -35,7 +35,7 @@ const wsOptions = {
onMounted(() => { onMounted(() => {
websocket.initialize(wsOptions); websocket.initialize(wsOptions);
websocket.on("message", async (res: any) => { websocket.on("message", async (res: any) => {
if (res && res && res.code === 200) { if (res && res.code === 200) {
const {data} = res; const {data} = res;
img.src = data; img.src = data;
await upscale.loadImg(img); await upscale.loadImg(img);
@@ -43,7 +43,16 @@ onMounted(() => {
} }
}); });
}); });
watch(
() => websocket.readyState,
(newStatus) => {
if (newStatus === WebSocket.OPEN) {
upscale.status = 'active';
} else {
upscale.status = 'loading';
}
}
);
onUnmounted(() => { onUnmounted(() => {
websocket.close(false); websocket.close(false);
}); });
@@ -87,7 +96,7 @@ onUnmounted(() => {
.upscale-content-right { .upscale-content-right {
width: 70%; width: 70%;
height: 100%; height: 100%;
border-radius: 10px;
} }
} }
} }

View File

@@ -236,10 +236,6 @@ self.onmessage = async function (e: MessageEvent): Promise<void> {
output.cropToOriginalSize(width_ori * factor, height_ori * factor); output.cropToOriginalSize(width_ori * factor, height_ori * factor);
} }
await new Promise((resolve) => setTimeout(resolve, 10)); await new Promise((resolve) => setTimeout(resolve, 10));
self.postMessage({
progress: 100,
info: `Processing image...`,
});
self.postMessage( self.postMessage(
{ {
progress: 100, progress: 100,