mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
feat: image support fast matting
This commit is contained in:
parent
d2f171e368
commit
53df4edd76
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-29 20:35:31
|
* @Date: 2021-08-29 20:35:31
|
||||||
* @Description: 七牛上传方法
|
* @Description: 七牛上传方法
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||||
* @LastEditTime: 2023-07-11 22:02:12
|
* @LastEditTime: 2023-10-05 16:11:55
|
||||||
*/
|
*/
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import api from '@/api/album'
|
import api from '@/api/album'
|
||||||
@ -18,7 +18,7 @@ export default {
|
|||||||
upload: async (file: File, options: Options, cb?: Function) => {
|
upload: async (file: File, options: Options, cb?: Function) => {
|
||||||
const win: any = window
|
const win: any = window
|
||||||
let name = ''
|
let name = ''
|
||||||
const suffix = file.type.split('/')[1] // 文件后缀
|
const suffix = file.type.split('/')[1] || 'png' // 文件后缀
|
||||||
if (!options.fullPath) {
|
if (!options.fullPath) {
|
||||||
// const DT: any = await exifGetTime(file) // 照片时间
|
// const DT: any = await exifGetTime(file) // 照片时间
|
||||||
const DT: any = new Date()
|
const DT: any = new Date()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @Date: 2023-07-11 23:50:22
|
* @Date: 2023-07-11 23:50:22
|
||||||
* @Description: 抠图组件
|
* @Description: 抠图组件
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||||
* @LastEditTime: 2023-09-30 12:23:39
|
* @LastEditTime: 2023-10-05 16:19:11
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="show" title="AI 智能抠图" width="650" @close="handleClose">
|
<el-dialog v-model="show" title="AI 智能抠图" width="650" @close="handleClose">
|
||||||
@ -29,15 +29,16 @@
|
|||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button v-show="rawImage" @click="clear">重新选择图片</el-button>
|
<el-button v-show="rawImage && toolModel" @click="clear">重新选择图片</el-button>
|
||||||
<el-button v-show="cutImage" type="primary" plain @click="download"> 下载 </el-button>
|
<el-button v-show="cutImage && toolModel" type="primary" plain @click="download"> 下载 </el-button>
|
||||||
|
<el-button v-show="cutImage && !toolModel" type="primary" plain @click="cutDone"> 完成 </el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
import { defineComponent, reactive, toRefs, nextTick } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { ElProgress } from 'element-plus'
|
import { ElProgress } from 'element-plus'
|
||||||
import { UploadFilled } from '@element-plus/icons-vue'
|
import { UploadFilled } from '@element-plus/icons-vue'
|
||||||
@ -47,7 +48,8 @@ import * as api from '@/api/ai'
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { uploader, UploadFilled, ElProgress },
|
components: { uploader, UploadFilled, ElProgress },
|
||||||
setup() {
|
emits: ['done'],
|
||||||
|
setup(props, { emit }) {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const state: any = reactive({
|
const state: any = reactive({
|
||||||
show: false,
|
show: false,
|
||||||
@ -58,6 +60,7 @@ export default defineComponent({
|
|||||||
percent: 0,
|
percent: 0,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
progressText: '',
|
progressText: '',
|
||||||
|
toolModel: true,
|
||||||
})
|
})
|
||||||
let fileName: string = 'unknow'
|
let fileName: string = 'unknow'
|
||||||
let isRuning: boolean = false
|
let isRuning: boolean = false
|
||||||
@ -90,9 +93,15 @@ export default defineComponent({
|
|||||||
} else alert('服务器繁忙,请稍等下重新尝试~')
|
} else alert('服务器繁忙,请稍等下重新尝试~')
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = () => {
|
const open = (file: File) => {
|
||||||
state.show = true
|
state.show = true
|
||||||
store.commit('setShowMoveable', false)
|
store.commit('setShowMoveable', false)
|
||||||
|
nextTick(() => {
|
||||||
|
if (file) {
|
||||||
|
selectFile(file)
|
||||||
|
state.toolModel = false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@ -122,6 +131,15 @@ export default defineComponent({
|
|||||||
state.percent < 100 ? requestAnimationFrame(run) : (isRuning = false)
|
state.percent < 100 ? requestAnimationFrame(run) : (isRuning = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cutDone = async () => {
|
||||||
|
const response = await fetch(state.cutImage)
|
||||||
|
const buffer = await response.arrayBuffer()
|
||||||
|
const file = new File([buffer], `cut_image_${Math.random()}.png`)
|
||||||
|
emit('done', file)
|
||||||
|
state.show = false
|
||||||
|
handleClose()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clear,
|
clear,
|
||||||
download,
|
download,
|
||||||
@ -130,6 +148,7 @@ export default defineComponent({
|
|||||||
open,
|
open,
|
||||||
handleClose,
|
handleClose,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
|
cutDone,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-29 18:17:13
|
* @Date: 2021-08-29 18:17:13
|
||||||
* @Description: 二次封装上传组件
|
* @Description: 二次封装上传组件
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||||
* @LastEditTime: 2023-07-12 15:12:07
|
* @LastEditTime: 2023-10-05 15:46:02
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<el-upload action="" accept="image/*" :http-request="upload" :show-file-list="false" multiple>
|
<el-upload action="" accept="image/*" :http-request="upload" :show-file-list="false" multiple>
|
||||||
@ -75,7 +75,7 @@ export default defineComponent({
|
|||||||
if (file.size <= 1024 * 1024) {
|
if (file.size <= 1024 * 1024) {
|
||||||
tempSimpleRes = await qiNiuUpload(file) // 队列有文件,执行上传
|
tempSimpleRes = await qiNiuUpload(file) // 队列有文件,执行上传
|
||||||
const { width, height }: any = await getImage(file)
|
const { width, height }: any = await getImage(file)
|
||||||
useNotification('上传成功', '目前没有用户系统,请注意别上传隐私照片哦!', { position: 'bottom-left' })
|
useNotification('上传成功', '公共测试账户,上传请注意保护隐私哦!', { position: 'bottom-left' })
|
||||||
context.emit('done', { width, height, url: _config.IMG_URL + tempSimpleRes.key }) // 单个文件进行响应
|
context.emit('done', { width, height, url: _config.IMG_URL + tempSimpleRes.key }) // 单个文件进行响应
|
||||||
} else useNotification('爱护小水管', '请上传小于 1M 的图片哦!', { type: 'error', position: 'bottom-left' })
|
} else useNotification('爱护小水管', '请上传小于 1M 的图片哦!', { type: 'error', position: 'bottom-left' })
|
||||||
uploading = false
|
uploading = false
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @Date: 2022-02-23 15:48:52
|
* @Date: 2022-02-23 15:48:52
|
||||||
* @Description: 图片列表组件 Bookshelf Layout
|
* @Description: 图片列表组件 Bookshelf Layout
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||||
* @LastEditTime: 2023-10-04 22:05:21
|
* @LastEditTime: 2023-10-05 16:10:21
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<ul ref="listRef" class="img-list-wrap" :style="{ paddingBottom: isShort ? '15px' : '200px' }" @scroll="scrollEvent($event)">
|
<ul ref="listRef" class="img-list-wrap" :style="{ paddingBottom: isShort ? '15px' : '200px' }" @scroll="scrollEvent($event)">
|
||||||
@ -222,6 +222,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
&__mask {
|
&__mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-09 11:41:53
|
* @Date: 2021-08-09 11:41:53
|
||||||
* @Description:
|
* @Description:
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||||
* @LastEditTime: 2023-07-12 12:50:39
|
* @LastEditTime: 2023-10-05 16:13:56
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div id="w-image-style">
|
<div id="w-image-style">
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<div class="options">
|
<div class="options">
|
||||||
<el-button v-if="innerElement.cropEdit" plain type="primary" @click="imgCrop(false)">完成</el-button>
|
<el-button v-if="innerElement.cropEdit" plain type="primary" @click="imgCrop(false)">完成</el-button>
|
||||||
<el-button v-else plain type="primary" @click="imgCrop(true)"><i class="icon sd-caijian" />裁剪</el-button>
|
<el-button v-else plain type="primary" @click="imgCrop(true)"><i class="icon sd-caijian" />裁剪</el-button>
|
||||||
<el-button @click="openImageCutout" plain>抠图</el-button>
|
<el-button plain @click="openImageCutout">抠图</el-button>
|
||||||
<!-- <uploader class="options__upload" @done="uploadImgDone">
|
<!-- <uploader class="options__upload" @done="uploadImgDone">
|
||||||
<el-button size="small" plain>替换图片</el-button>
|
<el-button size="small" plain>替换图片</el-button>
|
||||||
</uploader> -->
|
</uploader> -->
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<i style="padding: 0 8px; cursor: pointer" class="icon sd-queren" @click="imgCrop(false)" />
|
<i style="padding: 0 8px; cursor: pointer" class="icon sd-queren" @click="imgCrop(false)" />
|
||||||
</inner-tool-bar>
|
</inner-tool-bar>
|
||||||
<picBox ref="picBox" @select="selectDone" />
|
<picBox ref="picBox" @select="selectDone" />
|
||||||
<imageCutout ref="imageCutout" />
|
<imageCutout ref="imageCutout" @done="cutImageDone" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -73,6 +73,8 @@ import layerIconList from '@/assets/data/LayerIconList'
|
|||||||
import alignIconList from '@/assets/data/AlignListData'
|
import alignIconList from '@/assets/data/AlignListData'
|
||||||
import picBox from '@/components/business/picture-selector'
|
import picBox from '@/components/business/picture-selector'
|
||||||
import imageCutout from '@/components/business/image-cutout'
|
import imageCutout from '@/components/business/image-cutout'
|
||||||
|
import Qiniu from '@/common/methods/QiNiu'
|
||||||
|
import _config from '@/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: NAME,
|
name: NAME,
|
||||||
@ -242,7 +244,24 @@ export default {
|
|||||||
this.$refs.picBox.open()
|
this.$refs.picBox.open()
|
||||||
},
|
},
|
||||||
openImageCutout() {
|
openImageCutout() {
|
||||||
this.$refs.imageCutout.open()
|
fetch(this.innerElement.imgUrl)
|
||||||
|
.then((response) => response.blob())
|
||||||
|
.then((blob) => {
|
||||||
|
const file = new File([blob], `image_${Math.random()}.jpg`, { type: 'image/jpeg' })
|
||||||
|
this.$refs.imageCutout.open(file)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('获取图片失败:', error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 完成抠图
|
||||||
|
async cutImageDone(file) {
|
||||||
|
const qnOptions = { bucket: 'xp-design', prePath: 'user' }
|
||||||
|
const result = await Qiniu.upload(file, qnOptions)
|
||||||
|
const { width, height } = await getImage(file)
|
||||||
|
const url = _config.IMG_URL + result.key
|
||||||
|
await api.material.addMyPhoto({ width, height, url })
|
||||||
|
this.innerElement.imgUrl = url
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user