code: optimize image cutout

This commit is contained in:
ShawnPhang 2023-09-30 12:15:53 +08:00
parent d2df5c488b
commit 91088b98e3
11 changed files with 82 additions and 57 deletions

View File

@ -14,7 +14,6 @@
"publish-fast": "git add . && git commit -m 'build: auto publish' && sh script/publish.sh"
},
"dependencies": {
"@gradio/client": "^0.1.4",
"@palxp/color-picker": "^1.3.1",
"@scena/guides": "^0.18.1",
"@webtoon/psd": "^0.4.0",

24
src/api/ai.ts Normal file
View File

@ -0,0 +1,24 @@
/*
* @Author: ShawnPhang
* @Date: 2021-08-27 14:42:15
* @Description: AI相关接口
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-30 12:08:01
*/
import fetch from '@/utils/axios'
// 上传接口
export const upload = (file: File, cb: Function) => {
const formData = new FormData()
formData.append('file', file)
const extra = {
responseType: 'blob',
onUploadProgress: (progress: any) => {
cb(Math.floor((progress.loaded / progress.total) * 100), 0)
},
onDownloadProgress: (progress: any) => {
cb(100, Math.floor((progress.loaded / progress.total) * 100))
},
}
return fetch('https://res.palxp.cn/ai/upload', formData, 'post', {}, extra)
}

View File

@ -2,13 +2,15 @@
* @Author: ShawnPhang
* @Date: 2021-08-19 18:43:22
* @Description:
* @LastEditors: ShawnPhang <site: book.palxp.com>
* @LastEditTime: 2023-07-21 13:06:46
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-28 15:46:56
*/
import * as home from './home'
import * as material from './material'
import * as ai from './ai'
export default {
home,
material,
ai,
}

View File

@ -1,9 +1,9 @@
/*
* @Author: ShawnPhang
* @Date: 2021-08-27 14:42:15
* @Description:
* @LastEditors: ShawnPhang <site: book.palxp.com>
* @LastEditTime: 2023-07-21 11:19:04
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-28 11:24:13
*/
import fetch from '@/utils/axios'

View File

@ -135,13 +135,4 @@
box-shadow: 0 0 0 5000px rgba(255, 255, 255, 0.95);
z-index: 8;
}
.shelter-bg {
// background-color: #ffffff;
background-color: #f0f0f0;
background-image: linear-gradient(to top right, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), linear-gradient(to top right, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-position: 0 0, 8px 8px;
background-size: 16px 16px;
overflow: hidden;
user-select: none;
}
}

View File

@ -25,3 +25,12 @@
.line-clamp-2 {
-webkit-line-clamp: 2;
}
.transparent-bg {
background-color: #f0f0f0;
background-image: linear-gradient(to top right, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), linear-gradient(to top right, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-position: 0 0, 8px 8px;
background-size: 16px 16px;
overflow: hidden;
user-select: none;
}

View File

@ -3,21 +3,25 @@
* @Date: 2023-07-11 23:50:22
* @Description: 抠图组件
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-15 12:38:49
* @LastEditTime: 2023-09-30 12:10:31
-->
<template>
<el-dialog v-model="show" title="AI抠图(测试版)" width="650" @close="handleClose">
<el-dialog v-model="show" title="AI 智能抠图" width="650" @close="handleClose">
<uploader v-if="!rawImage" :hold="true" :drag="true" :multiple="true" class="uploader" @load="selectFile">
<div class="uploader__box">
<upload-filled style="width: 64px; height: 64px" />
<div class="el-upload__text">在此拖入或选择<em>上传图片</em></div>
</div>
<div class="el-upload__tip">支持 jpg png 格式的文件大小不超过 2M</div>
<div class="el-upload__tip">由于服务器带宽过低上传大小限制在 1M </div>
</uploader>
<el-progress v-if="!cutImage && progressText" :percentage="progress">
<el-button text>
{{ progressText }} <span v-show="progress">{{ progress }}%</span>
</el-button>
</el-progress>
<div class="content">
<div v-show="rawImage" v-loading="!cutImage" :style="{ width: offsetWidth ? offsetWidth + 'px' : '100%' }" class="scan-effect">
<img ref="raw" :src="rawImage" alt="" />
<div :style="{ right: 100 - percent + '%' }" class="bg"></div>
<div v-show="rawImage" v-loading="!cutImage" :style="{ width: offsetWidth ? offsetWidth + 'px' : '100%' }" class="scan-effect transparent-bg">
<img ref="raw" :style="{ 'clip-path': 'inset(0 0 0 ' + percent + '%)' }" :src="rawImage" alt="" />
<img v-show="cutImage" :src="cutImage" alt="结果图像" @mousemove="mousemove" />
<div v-show="cutImage" :style="{ left: percent + '%' }" class="scan-line"></div>
</div>
@ -33,14 +37,16 @@
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, onMounted, nextTick } from 'vue'
import { defineComponent, reactive, toRefs } from 'vue'
import { useStore } from 'vuex'
import { ElProgress } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import uploader from '@/components/common/Uploader/index.vue'
import _dl from '@/common/methods/download'
import * as api from '@/api/ai'
export default defineComponent({
components: { uploader, UploadFilled },
components: { uploader, UploadFilled, ElProgress },
setup() {
const store = useStore()
const state: any = reactive({
@ -50,18 +56,15 @@ export default defineComponent({
raw: null,
offsetWidth: 0,
percent: 0,
progress: 0,
progressText: '',
})
let app: any = null
let fileName: string = 'unknow'
let isRuning: boolean = false
onMounted(async () => {
app = await store.getters.app
})
const selectFile = async (file: File) => {
if (file.size > 1024 * 1024 * 2) {
alert('上传小于 2M 的图片')
if (file.size > 1024 * 1024) {
alert('上传图片超出限制')
return false
}
//
@ -70,10 +73,22 @@ export default defineComponent({
})
state.rawImage = URL.createObjectURL(file)
fileName = file.name
//
const result = await app.predict('/predict', [file, 'u2netp', ''])
state.rawImage && (state.cutImage = result?.data[0])
requestAnimationFrame(run)
//
const result: any = await api.upload(file, (up: number, dp: number) => {
if (dp) {
state.progressText = '导入中..'
state.progress = dp
} else {
state.progressText = up < 100 ? '上传中..' : '正在处理,请稍候..'
state.progress = up < 100 ? up : 0
}
dp === 100 && (state.progressText = '')
})
if (result.type !== 'application/json') {
const resultImage = URL.createObjectURL(result)
state.rawImage && (state.cutImage = resultImage)
requestAnimationFrame(run)
} else alert('服务器繁忙,请稍等下重新尝试~')
}
const open = () => {
@ -146,12 +161,6 @@ export default defineComponent({
object-fit: contain;
position: absolute;
}
.bg {
width: 100%;
height: 100%;
background: #ffffff;
position: absolute;
}
}
.scan-line {
@ -163,4 +172,8 @@ export default defineComponent({
// background-image: linear-gradient(to top, transparent, rgba(255, 255, 255, 0.7), transparent);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
}
.progress {
width: 100%;
}
</style>

View File

@ -1,10 +1,3 @@
/*
* @Author: ShawnPhang
* @Date: 2023-09-07 22:56:09
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-20 16:09:59
*/
// const prefix = import.meta.env
const prefix = process.env
@ -21,7 +14,6 @@ export default {
API_URL: 'https://palxp.cn:8887', // 服务端地址
SCREEN_URL: isDev ? 'http://localhost:7001' : '#{SCREEN_URL}', // 截图服务地址
IMG_URL: 'https://store.palxp.com/', // 七牛云资源地址
KT_URL: 'https://res.palxp.cn:5001', // 抠图服务地址
// ICONFONT_URL: '//at.alicdn.com/t/font_3223711_74mlzj4jdue.css',
ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap',
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_6qsac4kteu7.css?&display=swap',

View File

@ -3,11 +3,10 @@
* @Date: 2021-12-16 16:20:16
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-15 12:47:57
* @LastEditTime: 2023-09-28 17:42:25
*/
import mutations from './mutations'
import actions from './actions'
import { client } from '@gradio/client'
import _config from '@/config'
const all = {
@ -39,10 +38,6 @@ const all = {
fonts: (state: Type.Object) => {
return state.fonts
},
app: async (state: Type.Object) => {
!state.app && (state.app = await client(_config.KT_URL))
return state.app
},
},
mutations: {
...mutations,

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang
* @Date: 2021-07-13 02:48:38
* @Description: code为200时返回result结果对象
* @LastEditors: ShawnPhang <site: book.palxp.com>
* @LastEditTime: 2023-07-31 09:34:34
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-28 15:58:41
*/
import axios from 'axios'
import store from '@/store'

View File

@ -21,7 +21,7 @@
<!-- 用于挡住画布溢出部分因为使用overflow有bug. PS:如shadow没有透明度则可以完全遮挡元素 -->
<div class="shelter" :style="{ width: Math.floor((dPage.width * dZoom) / 100) + 'px', height: Math.floor((dPage.height * dZoom) / 100) + 'px' }"></div>
<!-- 提供一个背景图层以免遮挡穿帮 -->
<div class="shelter-bg" :style="{ width: Math.floor((dPage.width * dZoom) / 100) + 'px', height: Math.floor((dPage.height * dZoom) / 100) + 'px' }"></div>
<div class="shelter-bg transparent-bg" :style="{ width: Math.floor((dPage.width * dZoom) / 100) + 'px', height: Math.floor((dPage.height * dZoom) / 100) + 'px' }"></div>
</design-board>
<style-panel></style-panel>
</div>