🚸 优化自定义表情处理

This commit is contained in:
目棃
2025-03-25 14:05:19 +08:00
parent d15d78b73f
commit d430cd4672
3 changed files with 61 additions and 38 deletions

View File

@@ -52,6 +52,6 @@ const bgImage = computed<string>(() => {
}
.desc {
text-shadow: 0 0 2px var(--common-shadow-8);
text-shadow: 0 0 2px var(--common-shadow-t-8);
}
</style>

View File

@@ -1,22 +1,27 @@
<template>
<div class="tp-emo-box" title="自定义表情" @click="download()">
<TMiImg
:src="props.data.insert.custom_emoticon.url"
<div class="tp-emo-box" title="自定义表情" v-if="localUrl !== undefined">
<img
:src="localUrl"
@click="showOverlay = true"
:alt="props.data.insert.custom_emoticon.hash"
:ori="true"
/>
<div class="tp-emo-info" v-if="props.data.insert.custom_emoticon.size.width > 100">
自定义表情
</div>
</div>
<div v-else class="tp-image-load" :title="props.data.insert.custom_emoticon.url">
<v-progress-circular :indeterminate="true" color="primary" size="small" />
<span>加载中...</span>
</div>
<VpOverlayImage :image="image" v-model="showOverlay" v-model:link="localUrl" :ori="true" />
</template>
<script lang="ts" setup>
import TMiImg from "@comp/app/t-mi-img.vue";
import showSnackbar from "@comp/func/snackbar.js";
import { shallowRef } from "vue";
import { computed, onMounted, onUnmounted, ref } from "vue";
import { getImageBuffer, saveCanvasImg } from "@/utils/TGShare.js";
import { bytesToSize } from "@/utils/toolFunc.js";
import type { TpImage } from "./tp-image.vue";
import VpOverlayImage from "./vp-overlay-image.vue";
import { saveImgLocal } from "@/utils/TGShare.js";
type TpCustomEmoticon = {
insert: {
@@ -33,24 +38,28 @@ type TpCustomEmoticon = {
type TpEmoticonProps = { data: TpCustomEmoticon };
const props = defineProps<TpEmoticonProps>();
const buffer = shallowRef<Uint8Array | null>(null);
const localUrl = ref<string>();
const showOverlay = ref<boolean>(false);
const image = computed<TpImage>(() => {
return {
insert: { image: props.data.insert.custom_emoticon.url },
attributes: {
width: props.data.insert.custom_emoticon.size.width,
height: props.data.insert.custom_emoticon.size.height,
size: props.data.insert.custom_emoticon.size.file_size,
},
};
});
console.log("tp-emoticon", props.data.insert.custom_emoticon);
async function download(): Promise<void> {
const image = props.data.insert.custom_emoticon.url;
if (buffer.value === null) buffer.value = await getImageBuffer(image);
let size: number;
if (props.data.insert.custom_emoticon.size.file_size) {
size = props.data.insert.custom_emoticon.size.file_size;
} else size = buffer.value.byteLength;
if (size > 80000000) {
showSnackbar.warn(`图片过大(${bytesToSize(size)}),无法下载到本地`);
return;
}
const format = image.split(".").pop();
await saveCanvasImg(buffer.value, props.data.insert.custom_emoticon.hash, format);
}
onMounted(async () => {
localUrl.value = await saveImgLocal(props.data.insert.custom_emoticon.url);
});
onUnmounted(() => {
if (localUrl.value) URL.revokeObjectURL(localUrl.value);
});
</script>
<style lang="scss" scoped>
.tp-emo-box {
@@ -59,7 +68,7 @@ async function download(): Promise<void> {
width: fit-content;
align-items: center;
justify-content: center;
margin: 10px auto;
margin: 8px auto;
cursor: pointer;
}
@@ -67,24 +76,25 @@ async function download(): Promise<void> {
width: v-bind("props.data.insert.custom_emoticon.size.width + 'px'");
max-width: 100%;
height: auto;
border-radius: 10px;
border-radius: 4px;
}
.tp-emo-info {
position: absolute;
top: 0;
right: 0;
padding: 0 5px;
padding: 0 4px;
border-bottom: 1px solid var(--common-shadow-1);
border-left: 1px solid var(--common-shadow-1);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
background: var(--common-shadow-t-2);
border-bottom-left-radius: 10px;
border-top-right-radius: 10px;
box-shadow: -1px 1px 3px var(--common-shadow-2);
border-bottom-left-radius: 4px;
border-top-right-radius: 4px;
box-shadow: -1px 1px 4px var(--common-shadow-2);
font-family: var(--font-title);
font-size: 12px;
cursor: default;
white-space: nowrap;
}
</style>

View File

@@ -6,20 +6,27 @@
</div>
<div class="tpoi-bottom">
<div class="tpoi-info" v-if="props.image.attributes">
<p v-if="props.image.attributes.size">
大小{{ bytesToSize(props.image.attributes.size ?? 0) }}
<p v-if="props.image.attributes.size" class="tpoi-info-item">
<span>大小</span>
<span>{{ bytesToSize(props.image.attributes.size ?? 0) }}</span>
</p>
<p class="tpoi-info-item">
<span>尺寸</span>
<span>{{ props.image.attributes.width }}x{{ props.image.attributes.height }}</span>
</p>
<p class="tpoi-info-item">
<span>格式</span>
<span>{{ format }}</span>
</p>
<p>尺寸{{ props.image.attributes.width }}x{{ props.image.attributes.height }}</p>
<p>格式{{ format }}</p>
</div>
<div class="tpoi-tools">
<v-icon @click="setBlackBg" title="切换背景色" v-if="showOri">
mdi-format-color-fill
</v-icon>
<v-icon @click="showOri = true" title="查看原图" v-else>mdi-magnify</v-icon>
<v-icon @click="onCopy" title="复制到剪贴板" v-if="format !== 'gif'"
>mdi-content-copy</v-icon
>
<v-icon @click="onCopy" title="复制到剪贴板" v-if="format !== 'gif'">
mdi-content-copy
</v-icon>
<v-icon @click="onDownload" title="下载到本地">mdi-download</v-icon>
<v-icon @click="visible = false" title="关闭浮窗">mdi-close</v-icon>
</div>
@@ -149,6 +156,12 @@ async function onDownload(): Promise<void> {
color: white;
}
.tpoi-info-item {
position: relative;
display: flex;
flex-wrap: wrap;
}
.tpoi-tools {
display: flex;
padding: 8px;