mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
feat: add Image Extraction 🎉
This commit is contained in:
parent
4dd687d5a6
commit
ad302a6240
@ -15,6 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@palxp/color-picker": "^1.3.1",
|
||||
"@palxp/image-extraction": "^1.2.4",
|
||||
"@scena/guides": "^0.18.1",
|
||||
"@webtoon/psd": "^0.4.0",
|
||||
"axios": "^0.21.1",
|
||||
|
@ -3,10 +3,10 @@
|
||||
* @Date: 2023-07-11 23:50:22
|
||||
* @Description: 抠图组件
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-07 15:48:27
|
||||
* @LastEditTime: 2023-10-09 00:42:48
|
||||
-->
|
||||
<template>
|
||||
<el-dialog v-model="show" title="AI 智能抠图" width="650" @close="handleClose">
|
||||
<el-dialog v-model="show" title="AI 智能抠图" align-center 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" />
|
||||
@ -29,11 +29,13 @@
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button v-show="rawImage && toolModel" @click="clear">重新选择图片</el-button>
|
||||
<el-button v-show="rawImage && toolModel" @click="clear">清空重选</el-button>
|
||||
<el-button v-show="cutImage" type="primary" plain @click="edit">进入编辑模式</el-button>
|
||||
<el-button v-show="cutImage && toolModel" type="primary" plain @click="download"> 下载 </el-button>
|
||||
<el-button v-show="cutImage && !toolModel" v-loading="loading" type="primary" plain @click="cutDone"> {{ loading ? '上传中..' : '完成' }} </el-button>
|
||||
<el-button v-show="cutImage && !toolModel" v-loading="loading" type="primary" plain @click="cutDone"> {{ loading ? '上传中..' : '完成抠图' }} </el-button>
|
||||
</span>
|
||||
</template>
|
||||
<ImageExtraction ref="matting" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@ -48,9 +50,10 @@ import api from '@/api'
|
||||
import Qiniu from '@/common/methods/QiNiu'
|
||||
import _config from '@/config'
|
||||
import { getImage } from '@/common/methods/getImgDetail'
|
||||
import ImageExtraction from './ImageExtraction.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { uploader, UploadFilled, ElProgress },
|
||||
components: { uploader, UploadFilled, ElProgress, ImageExtraction },
|
||||
emits: ['done'],
|
||||
setup(props, { emit }) {
|
||||
const store = useStore()
|
||||
@ -65,6 +68,7 @@ export default defineComponent({
|
||||
progressText: '',
|
||||
toolModel: true,
|
||||
loading: false,
|
||||
matting: null,
|
||||
})
|
||||
let fileName: string = 'unknow'
|
||||
let isRuning: boolean = false
|
||||
@ -152,6 +156,14 @@ export default defineComponent({
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const edit = () => {
|
||||
state.matting.open(state.rawImage, state.cutImage, (base64: any) => {
|
||||
state.cutImage = base64
|
||||
state.percent = 0
|
||||
requestAnimationFrame(run)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
clear,
|
||||
download,
|
||||
@ -161,6 +173,7 @@ export default defineComponent({
|
||||
handleClose,
|
||||
...toRefs(state),
|
||||
cutDone,
|
||||
edit,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
106
src/components/business/image-cutout/ImageExtraction.vue
Normal file
106
src/components/business/image-cutout/ImageExtraction.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<!--
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2023-10-08 14:15:17
|
||||
* @Description: 手动抠图 - 修补擦除
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-09 01:28:11
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="show" align-center width="90%" @close="showMatting = false">
|
||||
<template #header>
|
||||
<div class="tool-wrap">
|
||||
<el-button type="primary" plain @click="done">确认应用</el-button>
|
||||
<el-radio-group v-model="isErasing" style="margin-left: 35px">
|
||||
<el-radio :label="false" size="large"> <b>修补画笔</b> <i class="icon sd-xiubu" /></el-radio>
|
||||
<el-radio :label="true" size="large"> <b>擦除画笔</b> <i class="icon sd-cachu" /></el-radio>
|
||||
</el-radio-group>
|
||||
<number-slider v-model="radius" class="slider-wrap" label="画笔尺寸" :showInput="false" labelWidth="90px" :maxValue="constants.RADIUS_SLIDER_MAX" :minValue="constants.RADIUS_SLIDER_MIN" :step="constants.RADIUS_SLIDER_STEP" />
|
||||
<number-slider v-model="hardness" class="slider-wrap" label="画笔硬度" :showInput="false" labelWidth="90px" :maxValue="constants.HARDNESS_SLIDER_MAX" :minValue="constants.HARDNESS_SLIDER_MIN" :step="constants.HARDNESS_SLIDER_STEP" />
|
||||
</div>
|
||||
</template>
|
||||
<matting v-if="showMatting" :hasHeader="false" @register="mattingStart" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, nextTick } from 'vue'
|
||||
import matting, { MattingType } from '@palxp/image-extraction'
|
||||
import { ElRadioGroup, ElRadio } from 'element-plus'
|
||||
import numberSlider from '@/components/modules/settings/numberSlider.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { matting, ElRadioGroup, ElRadio, numberSlider },
|
||||
setup() {
|
||||
const state: any = reactive({
|
||||
show: false,
|
||||
showMatting: false,
|
||||
isErasing: false,
|
||||
radius: 0, // 画笔尺寸
|
||||
brushSize: '', // 画笔尺寸:计算属性,显示值
|
||||
hardness: 0, // 画笔硬度
|
||||
hardnessText: '', // 画笔硬度:计算属性,显示值
|
||||
constants: {},
|
||||
})
|
||||
|
||||
const params: any = { raw: '', result: '' }
|
||||
let matting: MattingType | any = {}
|
||||
let callback: any = null // 传回自动抠图的回调
|
||||
|
||||
const mattingStart: any = (mattingOptions: MattingType) => {
|
||||
mattingOptions.initLoadImages(params.raw, params.result)
|
||||
state.isErasing = mattingOptions.isErasing
|
||||
state.radius = mattingOptions.radius
|
||||
state.hardness = mattingOptions.hardness
|
||||
state.constants = mattingOptions.constants
|
||||
matting = mattingOptions
|
||||
}
|
||||
|
||||
const open = async (raw: any, result: any, cb: any) => {
|
||||
state.show = true
|
||||
params.raw = raw
|
||||
params.result = result
|
||||
await nextTick()
|
||||
setTimeout(() => {
|
||||
state.showMatting = true
|
||||
}, 300)
|
||||
callback = cb
|
||||
}
|
||||
|
||||
const done = () => {
|
||||
state.show = false
|
||||
callback(matting.getResult())
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
open,
|
||||
done,
|
||||
mattingStart,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
:deep(.el-dialog__header) {
|
||||
padding: 10px 35px;
|
||||
// var(--el-dialog-padding-primary)
|
||||
}
|
||||
.tool-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
// .tool-left {
|
||||
// display: inline-flex;
|
||||
// flex: 1;
|
||||
// }
|
||||
.slider-wrap {
|
||||
margin-left: 35px;
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-02-11 18:48:23
|
||||
* @Description: 组件列表
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-07 15:06:23
|
||||
* @LastEditTime: 2023-10-08 22:57:34
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -14,8 +14,8 @@
|
||||
</div>
|
||||
<div class="header">其它</div>
|
||||
<div class="item" @click="openImageCutout">
|
||||
<i class="icon sd-w-table" />
|
||||
<div class="text"><span>AI抠图</span> <span class="desc">上传图像一键去除背景</span></div>
|
||||
<i class="icon sd-AI_zhineng" />
|
||||
<div class="text"><span>在线抠图</span> <span class="desc">上传图像一键去除背景</span></div>
|
||||
</div>
|
||||
<imageCutout ref="imageCutout" />
|
||||
</div>
|
||||
|
@ -2,13 +2,13 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-09 11:44:29
|
||||
* @Description: 数值滑块组件
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||
* @LastEditTime: 2023-06-29 15:41:38
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-09 00:20:23
|
||||
-->
|
||||
<template>
|
||||
<div id="number-slider">
|
||||
<span :style="{ width: labelWidth }" class="label">{{ label }}</span>
|
||||
<el-slider v-model="innerValue" :min="minValue" :max="maxValue" :step="step" input-size="small" show-input :show-tooltip="false" :show-input-controls="false" @change="changeValue"> </el-slider>
|
||||
<el-slider v-model="innerValue" :min="minValue" :max="maxValue" :step="step" input-size="small" :show-input="showInput" :show-tooltip="false" :show-input-controls="false" @change="changeValue"> </el-slider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -37,6 +37,9 @@ export default {
|
||||
step: {
|
||||
default: 1,
|
||||
},
|
||||
showInput: {
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'finish'],
|
||||
data() {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-09 11:41:53
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-07 15:46:30
|
||||
* @LastEditTime: 2023-10-09 00:59:44
|
||||
-->
|
||||
<template>
|
||||
<div id="w-image-style">
|
||||
@ -21,12 +21,12 @@
|
||||
<el-button style="width: 100%; margin-bottom: 12px" plain @click="openPicBox">替换图片</el-button>
|
||||
<div class="options">
|
||||
<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 plain @click="openImageCutout">抠图</el-button>
|
||||
<el-button v-else plain type="primary" @click="imgCrop(true)"><i class="icon sd-caijian" /> 裁剪</el-button>
|
||||
<el-button plain @click="openImageCutout"><i class="icon sd-AIkoutu" /> 抠图</el-button>
|
||||
<!-- <uploader class="options__upload" @done="uploadImgDone">
|
||||
<el-button size="small" plain>替换图片</el-button>
|
||||
</uploader> -->
|
||||
<el-button size="small" disabled plain @click="openCropper">图片美化</el-button>
|
||||
<el-button size="small" disabled plain @click="openCropper">美化</el-button>
|
||||
</div>
|
||||
<!-- <container-wrap @change="changeContainer" />
|
||||
<br /> -->
|
||||
@ -292,6 +292,9 @@ export default {
|
||||
margin-left: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.icon {
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-wrap {
|
||||
|
@ -16,6 +16,6 @@ export default {
|
||||
IMG_URL: 'https://store.palxp.com/', // 七牛云资源地址
|
||||
// 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',
|
||||
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_zubqmza1sdk.css',
|
||||
QINIUYUN_PLUGIN: 'https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/qiniu-js/2.5.5/qiniu.min.js',
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user