La cámara frontal se ajusta para disparar, y se agregan el marco de guía y el procesamiento de recorte y rotación de fotos.

El título llama a la cámara para disparar.

  1. parte html
    <div @click="getCamera()">
    	<span>拍照</span>
    </div>
    
    <div
      class="video-box"
      v-show="showImg"
    >
    	<video
    		ref="videos"
    		v-show="showImg && isShowVideo == true"
    		webkit-playsinline="true"
    		playsinline
    	></video>
    	
    	<!-- 取景框 -->
    	<div class="img_warp">
    		<img :src="../../assets/image/xxx.png" class="cover-img"/>
    	</div>
    	
    	<!-- 关闭按钮 -->
    	<van-button
    		class="close-take-photo"
    		@click.native="closeTakePhoto"
    	>×</van-button>
    	
    	<!-- 拍照按钮 -->
    	<van-button
    		id="snap"
    		class="snap-btn"
    		@click.native="closeVideo"
    	></van-button>
    </div>
    
    
  2. parte css
// 样式可根据聚体需求调整 

.video-box {
    
    
  width: 100%;
  height: 100%;
  /* background-color: rgba(75, 75, 75); */
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

/* 摄像头 */
video {
    
    
  /* z-index: 10; */
  /* margin-right: 50px; */
  height: 100%;
  /* 拍摄镜头以Y轴为轴线旋转180度 */
  // transform: rotateY(180deg);
  // -ms-transform: rotateY(180deg); /* IE 9 */
  // -moz-transform: rotateY(180deg); /* Firefox */
  // -webkit-transform: rotateY(180deg); /* Safari 和 Chrome */
  // -o-transform: rotateY(180deg); /* Opera */
  /* width: 100%; */
  /* margin: auto; */
}

/** 右上角关闭按钮 */
.close-take-photo {
    
    
  width: 30px;
  height: 30px;
  color: black;
  font-size: 20px;
  background-color: white;
  box-shadow: 0 0 10px #fff;
  border-radius: 15px;
  line-height: 30px;
  text-align: center;
  /** 定位 */
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 10;
}

/* 取景框 */
.img_warp {
    
    
  width: 80%;
  height: 70%;
  /* border: 1px black solid; */
  /* background-image: url("../../../assets/images/cover3.png");
  background-repeat: no-repeat;
  background-size: cover; */
  // position: fixed;
  // left: 0;
  // bottom: 0;
  // top: 0;
  // right: 0;
  z-index: 10;
}

.img_warp img {
    
    
  width: 80%;
  height: 65%;
  margin-left: 50%;
  transform: translateX(-50%);
  margin-top: 80px;
}

.cover-img {
    
    
  /* width: 300px; */
  /* height: 100%; */
  width: 100%;

  position: fixed;
  left: 0;
  bottom: 0;
  top: 0;
  right: 0;
}

/* 拍照按钮 */
.snap-btn {
    
    
  width: 50px;
  height: 50px;
  background: #fff;
  box-shadow: 0 0 5px #fff;
  border-radius: 50px;
  position: fixed;
  bottom: 20px;
  left: 50%;
  margin-left: -25px;
  z-index: 10;
}

/* 画布 */
canvas {
    
    
  width: 100%;
  /* height: 100%; */
  border: 1px;
}
  1. js parte
// 调用摄像头 开始拍照
getCamera () {
    
    
	// 注意本例需要在HTTPS协议网站中运行,新版本Chrome中getUserMedia接口在http下不再支持。
	// 设置事件监听器
	// window.addEventListener('DOMContentLoaded', function () {
    
    

	// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
	if (navigator.mediaDevices === undefined) {
    
    
 		navigator.mediaDevices = {
    
    }
 	}

	// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
	// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
	if (navigator.mediaDevices.getUserMedia === undefined) {
    
    
		navigator.mediaDevices.getUserMedia = function (constraints) {
    
    
			// 首先,如果有getUserMedia的话,就获得它
			// var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia
			var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia

			// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
			if (!getUserMedia) {
    
    
				alert('该浏览器不支持getUserMedia,请使用其他浏览器')
				return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
			}

			// 否则,为老的navigator.getUserMedia方法包裹一个Promise
			return new Promise(function (resolve, reject) {
    
    
				getUserMedia.call(navigator, constraints, resolve, reject)
			})
		}
	}
	
	// 获取手机屏幕宽度 赋给video
	let h = document.documentElement.clientHeight
	let w = document.documentElement.clientWidth
	var constraints = {
    
    
		audio: false,
		video: {
    
    
			// facingMode: 'user', // 调前置摄像头
			facingMode: 'environment', // 调后置摄像头
			//调整焦距及清晰度
			advanced: [
				{
    
     width: 1500, height: 2000 },
				{
    
     aspectRatio: 1 }
			]
		}
	}

	let _this = this

	navigator.mediaDevices.getUserMedia(constraints)
		.then((stream) => {
    
    
			_this.MediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0]
			// 显示取景框
			this.showImg = true
			// 显示画布 关闭摄像头
			this.isShowVideo = true
			this.isShowCanvas = false
			var video = document.querySelector('video')

      // 旧的浏览器可能没有srcObject
      if ('srcObject' in video) {
    
    
        video.srcObject = stream
      } else {
    
    
        // 防止在新的浏览器里使用它,应为它已经不再支持了
        video.src = window.URL.createObjectURL(stream)
      }

      //   var tracker = this.tracking.ObjectTracker('face')

      video.onloadedmetadata = function () {
    
    
        // 屏幕宽高
        video.style.height = h + 'px'
        // video实际宽高
        // console.log(video.videoWidth + ',' + video.videoHeight)

        // 偏移  video.videoWidth / video.videoHeight
        var videoW = (video.videoWidth / video.videoHeight) * h
        this.margin_left = (w - videoW) / 2

        // 控制左边不会出现空白的同时向右偏移
        // if (videoW - w > 60) {
    
    
        //   this.margin_left += 30
        // } else {
    
    
        //   this.margin_left += (videoW - w) / 2
        // }

        video.style.marginLeft = this.margin_left + 'px'

        // video实际宽度

        // 根据实际宽度 查找中间线
        // let mainLine = (video.videoWidth / 2 - w)
        // let mainLine = (video.videoWidth / 2 - w / 2)

        // // video.style.marginLeft = (w - video.videoWidth) / 2 + 'px'
        // video.style.marginLeft = -mainLine + 'px'

        video.play()
      }
    })
    .catch(function (err) {
    
     alert(err.name + ': ' + err.message) })

  // }, false)
},

// 点击拍照
closeVideo () {
    
    
	// 点击拍照 -> 关闭摄像头 ->显示画布
	this.isShowVideo = false
	this.isShowCanvas = true
	this.showImg = false

	var canvas = document.querySelector('#mycanvas')
	var ctx = canvas.getContext('2d')
	var video = document.querySelector('video')
	// var ctx = this.$refs.mycanvas.getContext('2d')

	canvas.height = 600
	canvas.width = (video.videoWidth * 600) / video.videoHeight

	ctx.drawImage(video, 0, 0, canvas.width, 600)
	this.dealVideoPhoto(canvas.toDataURL("image/jpeg", .8))
},

// 处理拍摄相片
dealVideoPhoto (base64Img) {
    
    
	// 输出相片base64
	console.log(base64Img);
},

// 取消拍照
closeTakePhoto () {
    
    
	// 刷新当前页面
	this.$router.go(0)
}

Procese fotos capturadas, recorte y rote

Se requieren los siguientes tres pasos para procesar las fotos capturadas y realizar el procesamiento de recorte y rotación:

  1. Convertir imagen base64 a objeto img
  2. recortar la imagen
  3. Gire la imagen y
    encapsule el método para convertir la base64 de la imagen en un objeto img, nombre el archivo xxx1.js y colóquelo en la carpeta utils
    // 将base64转换成img对象
    /**
     * 
     * @param {*} str 图片base64
     */
    export default function readBase64 (str) {
          
          
      return new Promise((resolve, reject) => {
          
          
        const img = new Image()
        img.src = 'data:image/jpeg;base64,' + str
        img.onload = function () {
          
          
          resolve(img)
        }
        img.onerror = function (e) {
          
          
          reject(e)
        }
      })
    }
    

Encapsule el método de recorte y rotación de la imagen, nombre el archivo xxx2.js y colóquelo en la carpeta utils

var img = null
var canvas = document.createElement("canvas");// 创建canvas对象
var ctx = canvas.getContext('2d');
/**
 * 
 * @param {*} imgObj 
 * @param {*} leftX 左上角X坐标
 * @param {*} leftY 左上角Y坐标
 * @param {*} rightX 右下角X坐标
 * @param {*} rightY 右下角Y坐标
 * @param {*} isRotate 是否旋转
 * @returns 
 */
export default function dealBase64Img (imgObj, leftX, leftY, rightX, rightY, isRotate) {
    
    
	return new Promise(resolve => {
    
    
		// 获取原图宽高
		var height = imgObj.height;
		var width = imgObj.width;
		//设置canvas大小与原图宽高一致
		canvas.height = height;
		canvas.width = width;
		// 在canvas绘制图片
		ctx.drawImage(imgObj, 0, 0, width, height);
		// 截图:
		drawRect(leftX, leftY, rightX, rightY);

		if (isRotate) {
    
    
			rotateBase64Img(img, 270).then(res => {
    
    
				resolve(res)
			})
		} else {
    
    
			resolve(img)
		}
	})
}

// 绘制截图矩阵
function drawRect (leftX, leftY, rightX, rightY) {
    
    
	// 截图宽度
	var w = rightX - leftX;
	// 截图高度
	var h = rightY - leftY;
	// 获取截图区域内容,截图区域的像素点矩阵
	var cutImage = ctx.getImageData(leftX, leftY, w, h);
	// 裁剪后的base64数据
	var newImage = createNewCanvas(cutImage, w, h);
	img = newImage;
	// console.log(newImage);// 裁剪后的base64数据
}

//创建新的空白canvas画布将矩阵渲染截图
function createNewCanvas (content, width, height) {
    
    
	var nCanvas = document.createElement('canvas');
	var nCtx = nCanvas.getContext('2d');
	nCanvas.width = width;
	nCanvas.height = height;
	nCtx.putImageData(content, 0, 0);// 将画布上指定矩形的像素数据,通过 putImageData() 方法将图像数据放回画布
	return nCanvas.toDataURL('image/png');
}

// 旋转图片
/**
 * 
 * @param {*} src 图片base64
 * @param {*} edg 旋转角度
 * @returns 
 */
function rotateBase64Img (src, edg) {
    
    
	return new Promise(resolve => {
    
    
		var canvas = document.createElement("canvas");
	    var ctx = canvas.getContext("2d");
		var imgW;//图片宽度
		var imgH;//图片高度
		var size;//canvas初始大小
		if (edg % 90 != 0) {
    
    
			console.error("旋转角度必须是90的倍数!");
			throw '旋转角度必须是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 = function () {
    
    
			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);

			resolve(canvas.toDataURL())
		};
	})
}

Finalmente, introduzca el método readBase64 de xxx1.js y el método dealBase64Img del archivo xxx2.js para procesar la base64 de la foto después de tomarla.

// 注意引入路径不要出错
import readBase64 from '@/utils/xxx1.js'
import dealBase64Img from '@/utils/xxx2.js'

dealVideoPhoto (base64Img) {
    
    
	// console.log(base64Img);
	const img = base64Img.replace(/^data:image\/\w+;base64,/, '')
      
	// 将base64转换成img对象
	readBase64(img).then(imgObj => {
    
    

		dealBase64Img(imgObj, 250, 60, 550, 480, true).then(res => {
    
    
			const img = res.replace(/^data:image\/\w+;base64,/, '')
			
			// 输出处理后的相片base64
			console.log(img)
        })
	}
}

Supongo que te gusta

Origin blog.csdn.net/lhh_gxx/article/details/128375968
Recomendado
Clasificación