mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
code: optimize image cutout
This commit is contained in:
parent
d2df5c488b
commit
91088b98e3
@ -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
24
src/api/ai.ts
Normal 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)
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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',
|
||||
|
@ -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,
|
||||
|
@ -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'
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user