vue3中使用 tui-image-editor进行图片处理,并上传

效果图

在这里插入图片描述

下载包

pnpm i tui-image-editor
pnpm i tui-color-picker

调用组件

//html部分
<el-dialog v-model="imgshow" destroy-on-close width="40%" draggable align-center :show-close="true"
				:close-on-click-modal="false">
				<template #header>
					<div style="display: flex; justify-content: space-between">
						<div style="display: flex">
							<h3>图片</h3>
						</div>
					</div>
				</template>
				<div class="newBox">
					<!-- 图片处理框 -->
					<SignImage v-if="cropperObj.cVisible" :dialogVisible="cropperObj.cVisible" :title="cropperObj.ctitle"
						:imgUrl="cropperObj.previewsImgUrl" @getNewImg="cropperObj.getNewImg"
						@closeCropperDialog="cropperObj.closeCropperView"></SignImage>

				</div>
			</el-dialog>

//js部分
import { SignImage } from './index';//调用组件
let imgshow = ref<boolean>(false);
const cropperObj = reactive({
	cVisible: true, // 显示切图弹框
	ctitle: "", // 弹框标题
	previewsImgUrl: "https://img0.baidu.com/it/u=2759734465,3558448225&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1708621200&t=acc59373dca9b8658e33e14a974f6c47", //图片地址
	// 开启剪切弹框
	openCropperView: () => {
		cropperObj.ctitle = "图片处理"
		cropperObj.cVisible = true
	},
	// 关闭弹框所触发的事件
	closeCropperView: (data) => {
		cropperObj.cVisible = false
	},
	// 获取处理完的图片数据
	getNewImg: (val: any) => {
		console.log("val", val);
		pictureAnnotationFun(val)
	}
})
//图片上传函数,并加其他参数
async function pictureAnnotationFun(file: any) {
	const formData = new FormData()
	formData.append("file", file);
	formData.append('id', xx);
	formData.append('bid', xxx);
	try {
		const { code, msg, data } = await uploadimg(formData);
		if (code > 0) {
			cropperObj.cVisible = false;
			ElMessage({
				showClose: true,
				message: '上传成功',
				type: 'success',
			});
		} else {
			ElMessage({
				showClose: true,
				message: '上传失败' + msg,
				type: 'error',
				duration: 0,
			});
		}
	} catch (e) {

		ElMessage({
			showClose: true,
			message: '错误: ' + e.message,
			type: 'error',
			duration: 0,
		});
	}
}


封装组件代码

<template>
	<div class="drawing-container">
		<!-- 绘图组件容器DOM -->
		<div id="tui-image-editor"></div>
		<el-button class="save" type="primary" @click="save">保存</el-button>
	</div>
</template>
<script setup lang="ts">
import 'tui-image-editor/dist/tui-image-editor.css';
import 'tui-color-picker/dist/tui-color-picker.css';
import ImageEditor from 'tui-image-editor';
import { nextTick, onMounted, ref } from 'vue';

// 中文菜单
const locale_zh = {
	ZoomIn: '放大',
	ZoomOut: '缩小',
	Hand: '手掌',
	History: '历史',
	Resize: '调整宽高',
	Crop: '裁剪',
	DeleteAll: '全部删除',
	Delete: '删除',
	Undo: '撤销',
	Redo: '反撤销',
	Reset: '重置',
	Flip: '镜像',
	Rotate: '旋转',
	Draw: '画',
	Shape: '形状标注',
	Icon: '图标标注',
	Text: '文字标注',
	Mask: '遮罩',
	Filter: '滤镜',
	Bold: '加粗',
	Italic: '斜体',
	Underline: '下划线',
	Left: '左对齐',
	Center: '居中',
	Right: '右对齐',
	Color: '颜色',
	'Text size': '字体大小',
	Custom: '自定义',
	Square: '正方形',
	Apply: '应用',
	Cancel: '取消',
	'Flip X': 'X 轴',
	'Flip Y': 'Y 轴',
	Range: '区间',
	Stroke: '描边',
	Fill: '填充',
	Circle: '圆',
	Triangle: '三角',
	Rectangle: '矩形',
	Free: '曲线',
	Straight: '直线',
	Arrow: '箭头',
	'Arrow-2': '箭头2',
	'Arrow-3': '箭头3',
	'Star-1': '星星1',
	'Star-2': '星星2',
	Polygon: '多边形',
	Location: '定位',
	Heart: '心形',
	Bubble: '气泡',
	'Custom icon': '自定义图标',
	'Load Mask Image': '加载蒙层图片',
	Grayscale: '灰度',
	Blur: '模糊',
	Sharpen: '锐化',
	Emboss: '浮雕',
	'Remove White': '除去白色',
	Distance: '距离',
	Brightness: '亮度',
	Noise: '噪音',
	'Color Filter': '彩色滤镜',
	Sepia: '棕色',
	Sepia2: '棕色2',
	Invert: '负片',
	Pixelate: '像素化',
	Threshold: '阈值',
	Tint: '色调',
	Multiply: '正片叠底',
	Blend: '混合色',
	Width: '宽度',
	Height: '高度',
	'Lock Aspect Ratio': '锁定宽高比例',
};

// 画布组件自定义样式
const customTheme = {
	'common.bi.image': '', // 左上角logo图片
	'common.bisize.width': '0px',
	'common.bisize.height': '0px',
	'common.backgroundImage': 'none',
	'common.backgroundColor': '#f3f4f6',
	'common.border': '1px solid #333',

	// header
	'header.backgroundImage': 'none',
	'header.backgroundColor': '#f3f4f6',
	'header.border': '0px',

	// load button
	'loadButton.backgroundColor': '#fff',
	'loadButton.border': '1px solid #ddd',
	'loadButton.color': '#222',
	'loadButton.fontFamily': 'NotoSans, sans-serif',
	'loadButton.fontSize': '12px',
	'loadButton.display': 'none', // 可以直接隐藏掉

	// download button
	'downloadButton.backgroundColor': '#fdba3b',
	'downloadButton.border': '1px solid #fdba3b',
	'downloadButton.color': '#fff',
	'downloadButton.fontFamily': 'NotoSans, sans-serif',
	'downloadButton.fontSize': '12px',
	'downloadButton.display': 'none', // 可以直接隐藏掉

	// icons default
	'menu.normalIcon.color': '#8a8a8a',
	'menu.activeIcon.color': '#555555',
	'menu.disabledIcon.color': '#ccc',
	'menu.hoverIcon.color': '#e9e9e9',
	'submenu.normalIcon.color': '#8a8a8a',
	'submenu.activeIcon.color': '#e9e9e9',

	'menu.iconSize.width': '24px',
	'menu.iconSize.height': '24px',
	'submenu.iconSize.width': '32px',
	'submenu.iconSize.height': '32px',

	// submenu primary color
	'submenu.backgroundColor': '#1e1e1e',
	'submenu.partition.color': '#858585',

	// submenu labels
	'submenu.normalLabel.color': '#858585',
	'submenu.normalLabel.fontWeight': 'lighter',
	'submenu.activeLabel.color': '#fff',
	'submenu.activeLabel.fontWeight': 'lighter',

	// checkbox style
	'checkbox.border': '1px solid #ccc',
	'checkbox.backgroundColor': '#fff',

	// rango style
	'range.pointer.color': '#fff',
	'range.bar.color': '#666',
	'range.subbar.color': '#d1d1d1',

	'range.disabledPointer.color': '#414141',
	'range.disabledBar.color': '#282828',
	'range.disabledSubbar.color': '#414141',

	'range.value.color': '#fff',
	'range.value.fontWeight': 'lighter',
	'range.value.fontSize': '11px',
	'range.value.border': '1px solid #353535',
	'range.value.backgroundColor': '#151515',
	'range.title.color': '#fff',
	'range.title.fontWeight': 'lighter',

	// colorpicker style
	'colorpicker.button.border': '1px solid #1e1e1e',
	'colorpicker.title.color': '#fff',
};

// props
const props = defineProps({
	dialogVisible: {
		type: Boolean,
		default: () => {
			return false;
		},
	},
	title: {
		type: String,
		default: '',
	},
	imgUrl: {
		type: String,
		default: '',
	},
});
const emit = defineEmits(['closeCropperDialog', 'getNewImg']);
const instance = ref<any>(null);

onMounted(() => {

	nextTick(() => {
		init(); // 页面创建完成后调用
	});
});

// 关闭弹框
const closeDialog = () => {
	emit('closeCropperDialog');
	// options.img = ''
};

const init = () => {
	instance.value = new ImageEditor(document.querySelector('#tui-image-editor'), {
		includeUI: {
			loadImage: {
				path: props.imgUrl,
				name: 'image',
			},
			menu: ['resize', 'crop', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
			initMenu: 'draw', // 默认打开的菜单项
			menuBarPosition: 'bottom', // 菜单所在的位置
			locale: locale_zh, // 本地化语言为中文
			theme: customTheme, // 自定义样式
		},
		cssMaxWidth: 400, // canvas 最大宽度
		cssMaxHeight: 500, // canvas 最大高度
	});
	document.getElementsByClassName('tui-image-editor-main')[0].style.top = '45px'; // 调整图片显示位置
	document.getElementsByClassName('tie-btn-reset tui-image-editor-item help')[0].style.display = 'none'; // 隐藏顶部重置按钮
};

// 保存图片,并上传
const save = async () => {
	const base64String = instance.value.toDataURL(); // base64 文件
	const data = window.atob(base64String.split(',')[1]);
	const ia = new Uint8Array(data.length);
	for (let i = 0; i < data.length; i++) {
		ia[i] = data.charCodeAt(i);
	}
	const file = new File([ia], "打标.png", { type: "image/png" });
	emit('getNewImg', file);

};
</script>

<style lang="scss" scoped>
.drawing-container {
	width: 100%;
	height: 80vh;
	position: relative;

	.save {
		position: absolute;
		right: 50px;
		top: 15px;
	}
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/401293.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

“成像光谱遥感技术中的AI革命:ChatGPT应用指南“

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本课程重点介绍ChatGPT在遥感中的应用&#xff0c;人工智…

Redis篇----第六篇

系列文章目录 文章目录 系列文章目录前言一、Redis 的持久化机制是什么?各自的优缺点?二、Redis 常见性能问题和解决方案:三、redis 过期键的删除策略?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章…

h5网页和 Android APP联调,webview嵌入网页,网页中window.open打开新页面,网页只在webview中打开,没有重开一个app窗口

我是h5网页开发&#xff0c;客户app通过webview嵌入我的页面 点击标题window.open跳转到长图页面&#xff0c;客户的需求是在app里新开一个窗口展示长图页面&#xff0c;window.open打开&#xff0c;ios端是符合客户需求的&#xff0c;但是在安卓端他会在当前webview打开 这…

消息队列-RabbitMQ:死信队列

十五、死信队列 1、死信的概念 先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理解&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c;consumer 从 que…

【Chrono Engine学习总结】4-vehicle-4.3-两个vehicle碰撞测试

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 今天突发奇想&#xff0c;想试一下&#xff0c;是否可以实现两个vehicle的碰撞&#xff1f; 1、两辆vehicle的仿真 官方提供了demo_VEH_TwoCars这个demo&#xff0c…

【更新公告】AirtestIDE更新至1.2.17版本

1. 前言 本次更新为AirtestIDE、Airtest-Selenium库更新。 AirtestIDE更新至1.2.17版本&#xff0c;AirtestIDE内置库Airtest更新为1.3.3.1版本&#xff0c;Poco更新为1.0.94版本&#xff0c;主要支持了selenium4.0以上版本&#xff0c;ADB更换为41版本&#xff0c;Airtest新…

数据驱动决策:掌握高效数据分析的七大步骤

在这个数据驱动的时代&#xff0c;无论是企业决策还是个人发展&#xff0c;数据分析都扮演着至关重要的角色。然而&#xff0c;想要从海量数据中提炼出有价值的信息&#xff0c;并不是一件容易的事情。本文为你详细解读高效数据分析&#xff0c;让你的数据开口说话&#xff0c;…

GIS技术在灾后重建中的空间规划与决策支持

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

单体微服务K8S笔记

单体微服务K8S笔记 https://blog.csdn.net/m0_48341969/article/details/126063832思路参考以上博客 //测试 https://gitee.com/yangbuyi/yi项目组织参考以上git 单体&#xff1a; 不特地介绍 微服务&#xff1a; rpc:远程过程调用 拆分&#xff0c;分别部署&#xff0…

Day04-流程控制语句_循环结构(while,do...while,关键字continue,关键字break,循环嵌套)

文章目录 Day04- 循环结构学习目标1 while循环2 do...while循环4 循环语句的区别5 关键字continue6 关键字break7 循环嵌套案例1&#xff1a;打印5行直角三角形案例2&#xff1a;break结束当层循环 Day04- 循环结构 学习目标 理解for语句的格式和执行流程 随机数公式 理解…

Linux中安装Nginx及日常配置使用

高性能的http服务器/反向代理服务器。官方测试支持5万并发&#xff0c;CPU、内存等消耗较低且运行稳定 使用场景 Http服务器。 Nginx可以单独提供Http服务&#xff0c;做为静态网页的服务器。虚拟主机。 可以在一台服务器虚拟出多个网站。反向代理与负载均衡。 Nginx做反向代理…

SQL注入之DNSLog外带注入

一、认识&#xff1a; 什么是dnslog呢&#xff1f; DNS就是域名解析服务&#xff0c;把一个域名转换成对应的IP地址&#xff0c;转换完成之后&#xff0c;DNS服务器就会有一个日志记录本次转换的时间、域名、域名对应的ip、请求方的一些信息&#xff0c;这个日志就叫DNSLog。…

基于 java springboot+layui仓库管理系统

基于 java springbootlayui仓库管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源…

好书推荐| After Effects 2022案例实战全视频教程

After Effects 2022案例实战全视频教程 作者 &#xff1a;王红卫 书号&#xff1a;9787302631958 定价&#xff1a;99元 出版时间&#xff1a;2023年7月 作者介绍 王红卫 拥有多年设计师的经学经验&#xff0c;北京理工大学百事特教师&#xff0c;水木风云工作室创始人&a…

网络编程知识整理

目录 1.1 引言 1.2 分层 1.3 TCP/IP的分层 1.4 互联网的地址 1.5 域名服务 1.6 封装 1.7 分用 1.8 端口号 1.1 引言 很多不同的厂家生产各种型号的计算机&#xff0c;它们运行完全不同的操作系统&#xff0c;但 T C P / I P协议族允许它们互相进行通信。这一点很让人感…

⭐北邮复试刷题105. 从前序与中序遍历序列构造二叉树__递归分治 (力扣每日一题)

105. 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,…

论文精读--word2vec

word2vec从大量文本语料中以无监督方式学习语义知识&#xff0c;是用来生成词向量的工具 把文本分散嵌入到另一个离散空间&#xff0c;称作分布式表示&#xff0c;又称为词嵌入&#xff08;word embedding&#xff09;或词向量 Abstract We propose two novel model architec…

Go 中的 init 如何用?它的常见应用场景有哪些呢?

嗨&#xff0c;大家好&#xff01;我是波罗学。本文是系列文章 Go 技巧第十六篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 Go 中有一个特别的 init() 函数&#xff0c;它主要用于包的初始化。init() 函数在包被引入后会被自动执行。如果在 main 包中&#xff0c;它也…

四、分类算法 - 随机森林

目录 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结 sklearn转换器和估算器KNN算法模型选择和调优朴素贝叶斯算法决策树随机森林 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结

Kubernetes 卷存储 NFS | nfs搭建配置 原理介绍 nfs作为存储卷使用

1、NFS介绍 NFS&#xff08;Network File System&#xff09;是一种分布式文件系统协议&#xff0c;允许客户端远程访问服务器上的文件&#xff0c;实现数据共享。它整合多个存储设备为统一文件系统&#xff0c;方便数据存储和管理&#xff0c;支持负载均衡和故障转移&#xf…
最新文章