base64图片旋转后得到一个base64图片
1.vue-esign签名插件
2.生成图片的图片的旋转
//第一个base64地址, 第二个顺时针角度, 第三个回调函数
this.rotateBase64Img(src, edg, data => {
console.log("旋转后的base64", data);
})
// 旋转图片
rotateBase64Img(src, edg, callback) {
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var imgW // 图片宽度
var imgH // 图片高度
var size // canvas初始大小
if (edg % 90 !== 0) {
console.error('旋转角度必须是90的倍数!')
return '旋转角度必须是90的倍数!'
}
edg < 0 && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4 // 旋转象限
const cutCoor = {
sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
var image = new Image()
image.crossOrigin = 'Anonymous'
image.src = src
image.onload = () => {
imgW = image.width
imgH = image.height
size = imgW > imgH ? imgW : imgH
canvas.width = size * 2
canvas.height = size * 2
switch (quadrant) {
case 0:
cutCoor.sx = size
cutCoor.sy = size
cutCoor.ex = size + imgW
cutCoor.ey = size + imgH
break
case 1:
cutCoor.sx = size - imgH
cutCoor.sy = size
cutCoor.ex = size
cutCoor.ey = size + imgW
break
case 2:
cutCoor.sx = size - imgW
cutCoor.sy = size - imgH
cutCoor.ex = size
cutCoor.ey = size
break
case 3:
cutCoor.sx = size
cutCoor.sy = size - imgW
cutCoor.ex = size + imgH
cutCoor.ey = size + imgW
break
}
ctx.translate(size, size)
ctx.rotate((edg * Math.PI) / 180)
ctx.drawImage(image, 0, 0)
var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey)
if (quadrant % 2 === 0) {
canvas.width = imgW
canvas.height = imgH
} else {
canvas.width = imgH
canvas.height = imgW
}
ctx.putImageData(imgData, 0, 0)
// callback(dataURLtoFileBlob(src))
callback(canvas.toDataURL())
// callback(canvas.toDataURL())
}
},
3.将 base64的图片 转换为 file 对象
// 附:base64转化成图片
base64ImgtoFile (dataurl, fileName = "file") {
const arr = dataurl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const suffix = mime.split("/")[1];
const bstr = atob(arr[1]);
let n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], `${
fileName}.${
suffix}`, {
type: mime });
},
============================================================================
实例代码
<template>
<div>
<div class="NavBar">
<bn-navBar title="电子签名" :leftArrow="false"></bn-navBar>
</div>
<div>
<div class="SignPlace">
<vue-esign
ref="esign"
class="esign-box"
:width="windowWidth"
:height="750"
:isCrop="isCrop"
:lineWidth="lineWidth"
:lineColor="lineColor"
/>
<!-- 写好的签字会放在这个图片里 -->
<img :src="imgSrc" width="400" :height="windowHeight" v-if="false" />
</div>
<div class="SignTips" id="main">
<span id="TipSpan">请在上方空白处书写您的名字</span>
<van-button type="info" @click="handleGenerate">提交签字</van-button>
<van-button
plain
type="info"
style="background-color: transparent"
@click="handleReset"
>清除重写</van-button
>
</div>
</div>
</div>
</template>
<script>
const environment = process.env.VUE_APP_ENV || 'production'
import {
Toast } from "vant";
import axios from "axios";
import {
setMoSignature, getCosInfo } from "../../api/register";
export default {
data () {
return {
lineWidth: 5,
lineColor: "black",
resultImg: "",
isCrop: false,
imgSrc: "",
signImage: null,
windowWidth: document.documentElement.clientWidth, //获取屏幕宽度
windowHeight: window.innerHeight, //获取屏幕高度
};
},
created () {
console.log(
"document.documentElement.clientHeight",
document.documentElement.clientHeight
);
console.log("this.$route.params", this.$route.params);
},
methods: {
handleReset () {
this.$refs.esign.reset();
},
// 生成签名的base64图片 提交
handleGenerate () {
this.$refs.esign.generate()
.then((res) => {
// 1.先将签名旋转 res-旋转前base64, data-旋转后base64
this.rotateBase64Img(res, 270, data => {
// 打印旋转后的图片base64
console.log('data', data);
// 2.将base64文件转为File文件-图片
this.imgSrc = res
const file = this.base64ImgtoFile(data);
console.log('res', res);
// 3.再将签名提交到
const that = this;
if (file) {
console.log("file", file);
this.getCosInfoFn(file);
}
})
})
.catch((err) => {
const errorMessage = "提交签名时出错,因为还未进行签字。";
Toast("请设置签名");
console.error(errorMessage);
console.log("画布没有签字时会执行这里 Not Signned");
});
},
// 附:base64转化成图片
base64ImgtoFile (dataurl, fileName = "file") {
const arr = dataurl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const suffix = mime.split("/")[1];
const bstr = atob(arr[1]);
let n = bstr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], `${
fileName}.${
suffix}`, {
type: mime });
},
// 提交
async submitNextFn (data) {
console.log('提交啦··········!,this.signImage', this.signImage)
const res = await setMoSignature({
signatureImgUrl: this.signImage,
signatureId: Number(this.$route.query.signatureId)
});
console.log('签名已提交1a', res);
if (res.code == 200) {
this.$router.push('/signingSuccess')
} else {
Toast(res.message);
}
},
// 获取cos签名
async getCosInfoFn (file, data) {
const res = await getCosInfo({
scene: "product_drug",
suffix: file.name.split(".").pop().toLowerCase(),
size: file.size,
});
console.log("获取cos签名", res);
if (res.status === 200) {
var xhr = new XMLHttpRequest();
xhr.open("PUT", res.data.url, true);
xhr.onload = function (e) {
};
xhr.onerror = function (e) {
that.$message({
message: "上传错误",
type: "error",
});
};
xhr.send(file);
this.signImage = res.data.returnUrl;
this.submitNextFn();
console.log("获取cos签名url", res.data.returnUrl);
}
},
// 旋转图片
rotateBase64Img(src, edg, callback) {
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var imgW // 图片宽度
var imgH // 图片高度
var size // canvas初始大小
if (edg % 90 !== 0) {
console.error('旋转角度必须是90的倍数!')
return '旋转角度必须是90的倍数!'
}
edg < 0 && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4 // 旋转象限
const cutCoor = {
sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
var image = new Image()
image.crossOrigin = 'Anonymous'
image.src = src
image.onload = () => {
imgW = image.width
imgH = image.height
size = imgW > imgH ? imgW : imgH
canvas.width = size * 2
canvas.height = size * 2
switch (quadrant) {
case 0:
cutCoor.sx = size
cutCoor.sy = size
cutCoor.ex = size + imgW
cutCoor.ey = size + imgH
break
case 1:
cutCoor.sx = size - imgH
cutCoor.sy = size
cutCoor.ex = size
cutCoor.ey = size + imgW
break
case 2:
cutCoor.sx = size - imgW
cutCoor.sy = size - imgH
cutCoor.ex = size
cutCoor.ey = size
break
case 3:
cutCoor.sx = size
cutCoor.sy = size - imgW
cutCoor.ex = size + imgH
cutCoor.ey = size + imgW
break
}
ctx.translate(size, size)
ctx.rotate((edg * Math.PI) / 180)
ctx.drawImage(image, 0, 0)
var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey)
if (quadrant % 2 === 0) {
canvas.width = imgW
canvas.height = imgH
} else {
canvas.width = imgH
canvas.height = imgW
}
ctx.putImageData(imgData, 0, 0)
// callback(dataURLtoFileBlob(src))
callback(canvas.toDataURL())
// callback(canvas.toDataURL())
}
},
},
// 兼容屏幕
watch: {
windowHeight (val) {
let that = this;
console.log("实时屏幕高度:", val, that.windowHeight);
},
windowWidth (val) {
let that = this;
console.log("实时屏幕宽度:", val, that.windowHeight);
},
},
};
</script>
<style scoped lang="less">
.body {
position: relative;
width: 100%;
height: 100%;
}
/deep/.van-nav-bar__title {
font-weight: 550;
}
.SignTips {
width: 10%;
height: 22%;
}
#TipSpan {
font-size: 4vw;
line-height: 22vw;
margin-left: 20vw;
}
.van-button {
float: right;
top: 6vw;
margin-right: 4vw;
border-radius: 12px;
height: 10vw;
width: 30vw;
}
.SignPlace {
position: absolute;
width: 100%;
height: 100%;
}
#main {
position: fixed;
padding: 0;
margin: 0;
overflow: hidden;
}
#main {
position: absolute;
width: 100vh;
height: 20vw;
top: 0;
left: 20vw;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
transform-origin: 0% 0%;
}
@media screen and (orientation: landscape) {
#main {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
}
html,body{
width:100%;
height: 100%;
}
.esign-box {
width: 100%;
height: 100%;
}
</style>