js realizes frame selection screen capture function

The idea of ​​​​the realization is probably to convert the dom into a canvas canvas first, then cut the canvas, and then generate a picture through the canvas api. A library is used herehtml2canvas

The effect is as shown in the figure:
insert image description here
First, realize the frame selection effect:

const mousedownEvent = (e) => {
    
    
	moveX = 0;
	moveY = 0;
	const [startX, startY] = [e.clientX, e.clientY];
	x = startX - viewer.getBoundingClientRect().left;
	y = startY - viewer.getBoundingClientRect().top;
	const divDom = document.createElement("div");
	divDom.id = 'screenshot';
	divDom.width = '1px';
	divDom.height = '1px';
	divDom.style.position = "absolute";
	divDom.style.top = y + "px";
	divDom.style.left = x + "px";
	const closeIcon = document.createElement("span");
	closeIcon.className = 'outline-close-icon';
	closeIcon.textContent = 'x';
	divDom.appendChild(closeIcon);

	closeIcon.addEventListener('click', () => {
    
    
		divDom.remove();
	});
	// document.body.appendChild(divDom)
	viewer.appendChild(divDom);
	const moveEvent = (e) => {
    
    
		moveX = e.clientX - startX;
		moveY = e.clientY - startY;
		if (moveX > 0) {
    
    
			divDom.style.width = moveX + 'px';
		} else {
    
    
			divDom.style.width = -moveX + 'px';
			divDom.style.left = e.clientX - viewer.getBoundingClientRect().left + 'px';
		}
		if (moveY > 0) {
    
    
			divDom.style.height = moveY + 'px';
		} else {
    
    
			divDom.style.height = -moveY + 'px';
			divDom.style.top = e.clientY - viewer.getBoundingClientRect().top + 'px';
		}
	};
	window.addEventListener("mousemove", moveEvent);
	window.addEventListener("mouseup", () => {
    
    
		window.removeEventListener("mousemove", moveEvent);
		window.removeEventListener("mousedown", mousedownEvent);
		document.querySelector("body").style.cursor = "default";
	});
};
window.addEventListener("mousedown", mousedownEvent);

Full size:

const viewer = document.getElementById('viewer');

document.getElementById('screen-button').addEventListener('click', (e) => {
    
    

	document.querySelector("body").style.cursor = "crosshair";
	let moveX;
	let moveY;
	let x;
	let y;
	const mousedownEvent = (e) => {
    
    
		moveX = 0;
		moveY = 0;
		const [startX, startY] = [e.clientX, e.clientY];
		x = startX - viewer.getBoundingClientRect().left;
		y = startY - viewer.getBoundingClientRect().top;
		const divDom = document.createElement("div");
		divDom.id = 'screenshot';
		divDom.width = '1px';
		divDom.height = '1px';
		divDom.style.position = "absolute";
		divDom.style.top = y + "px";
		divDom.style.left = x + "px";
		const closeIcon = document.createElement("span");
		closeIcon.className = 'outline-close-icon';
		closeIcon.textContent = 'x';
		divDom.appendChild(closeIcon);

		closeIcon.addEventListener('click', () => {
    
    
			divDom.remove();
		});
		// document.body.appendChild(divDom)
		viewer.appendChild(divDom);
		const moveEvent = (e) => {
    
    
			moveX = e.clientX - startX;
			moveY = e.clientY - startY;
			if (moveX > 0) {
    
    
				divDom.style.width = moveX + 'px';
			} else {
    
    
				divDom.style.width = -moveX + 'px';
				divDom.style.left = e.clientX - viewer.getBoundingClientRect().left + 'px';
			}
			if (moveY > 0) {
    
    
				divDom.style.height = moveY + 'px';
			} else {
    
    
				divDom.style.height = -moveY + 'px';
				divDom.style.top = e.clientY - viewer.getBoundingClientRect().top + 'px';
			}
		};
		window.addEventListener("mousemove", moveEvent);
		window.addEventListener("mouseup", () => {
    
    

			window.removeEventListener("mousemove", moveEvent);
			window.removeEventListener("mousedown", mousedownEvent);
			document.querySelector("body").style.cursor = "default";

			if (!moveX) {
    
    
				return;
			}

			// 把body转成canvas
			html2canvas(viewer, {
    
    
				scale: 1,
				// allowTaint: true,
				useCORS: true  //跨域使用
			}).then(canvas2 => {
    
    
				let capture_x, capture_y;
				let width = moveX;
				let height = moveY;
				if (width > 0) {
    
    
					//从左往右画
					capture_x = startX - canvas.getBoundingClientRect().left + 1;
				} else {
    
    
					//从右往左画
					capture_x = x + width + 1;
				}
				if (height > 0) {
    
    
					//从上往下画
					capture_y = y + 1;
				} else {
    
    
					//从下往上画
					capture_y = y + height + 1;
				}
				printClip(canvas2, capture_x, capture_y, Math.abs(width), Math.abs(height));

				moveX = 0;
		
			});
		});
	};
	window.addEventListener("mousedown", mousedownEvent);
});

/**
 * 打印截取区域
 * @param canvas 截取的canvas
 * @param capture_x 截取的起点x
 * @param capture_y 截取的起点y
 * @param capture_width 截取的起点宽
 * @param capture_height 截取的起点高
 */
async function printClip(canvas2, capture_x, capture_y, capture_width, capture_height) {
    
    
	// 创建一个用于截取的canvas
	const clipCanvas = document.createElement('canvas');
	clipCanvas.width = capture_width;
	clipCanvas.height = capture_height;
	// 截取
	clipCanvas.getContext('2d').drawImage(canvas2, capture_x, capture_y, capture_width, capture_height, 0, 0, capture_width, capture_height);
	const clipImgBase64 = clipCanvas.toDataURL();
	// console.log('clipImgBase64->', clipImgBase64);
	// console.log('clipImgBase64->', clipImgBase64.replace(/^data:image\/\w+;base64,/, ""));
	const obj = {
    
    
		// file: new File([this.blob],'main.audio',{ type: 'audio/mp3' })
		file: new File([base64ToBlob(clipImgBase64.replace(/^data:image\/\w+;base64,/, ""), 'image/png')], 'test.png', {
    
     type: 'image/png' })
	};
	// 生成图片
	// var clipImg = new Image()
	// clipImg.src = clipImgBase64
	downloadIamge(clipImgBase64)
}

/**
 * 下载保存图片
 * @param imgUrl 图片地址
 */
function downloadIamge(imgUrl) {
    
    
	// 生成一个a元素
	const a = document.createElement('a');
	// 创建一个单击事件
	const event = new MouseEvent('click');
	// 生成文件名称
	const timestamp = new Date().getTime();
	const name = imgUrl.substring(22, 30) + timestamp + '.png';
	a.download = name;
	// 将生成的URL设置为a.href属性
	a.href = imgUrl;
	// 触发a的单击事件 开始下载
	a.dispatchEvent(event);
}

// 将Base64编码转换为Blob对象
function base64ToBlob(base64, type) {
    
    
	const byteCharacters = atob(base64);
	const byteArrays = [];

	for (let offset = 0; offset < byteCharacters.length; offset += 512) {
    
    
		let slice = byteCharacters.slice(offset, offset + 512);

		let byteNumbers = new Array(slice.length);
		for (let i = 0; i < slice.length; i++) {
    
    
			byteNumbers[i] = slice.charCodeAt(i);
		}

		let byteArray = new Uint8Array(byteNumbers);
		byteArrays.push(byteArray);
	}

	let blob = new Blob(byteArrays, {
    
     type: type });
	return blob;
}

pit:

  1. If there is a problem with the generated image style html, use the inline style
  2. When taking a screenshot, if it is not recognized, convert the image url to base64
  3. When encountering a super long screenshot, it will fail. Let me talk about it in detail below.

The principle of our screenshot is to draw the page on the canvas, but here canvas在不同浏览器中高度都是有限制的, and the restrictions of different browsers are different, so that the long pdf page cannot be drawn on the canvas. The solution is to set a maximum height limit, and start the screenshot from the visible area , so that no matter how long the pdf preview page is, you can make a frame selection screenshot.

const viewer = document.getElementById('viewer');
		document.getElementById('screen-button').addEventListener('click', (e) => {
    
    

			document.querySelector("body").style.cursor = "crosshair";
			let moveX;
			let moveY;
			let x;
			let y;
			const mousedownEvent = (e) => {
    
    
				moveX = 0;
				moveY = 0;
				const [startX, startY] = [e.clientX, e.clientY];
				x = startX - viewer.getBoundingClientRect().left;
				y = startY - 64;
				const divDom = document.createElement("div");
				divDom.id = 'screenshot';
				divDom.width = '1px';
				divDom.height = '1px';
				divDom.style.position = "absolute";
				divDom.style.top = y + "px";
				divDom.style.left = x + "px";
				const closeIcon = document.createElement("span");
				closeIcon.className = 'outline-close-icon';
				closeIcon.textContent = 'x';
				divDom.appendChild(closeIcon);

				closeIcon.addEventListener('click', () => {
    
    
					divDom.remove();
				});
				// document.body.appendChild(divDom)
				viewer.appendChild(divDom);
				const moveEvent = (e) => {
    
    
					moveX = e.clientX - startX;
					moveY = e.clientY - startY;
					if (moveX > 0) {
    
    
						divDom.style.width = moveX + 'px';
					} else {
    
    
						divDom.style.width = -moveX + 'px';
						divDom.style.left = e.clientX - viewer.getBoundingClientRect().left + 'px';
					}
					if (moveY > 0) {
    
    
						divDom.style.height = moveY + 'px';
					} else {
    
    
						divDom.style.height = -moveY + 'px';
						divDom.style.top = e.clientY - viewer.getBoundingClientRect().top + 'px';
					}
				};
				window.addEventListener("mousemove", moveEvent);
				window.addEventListener("mouseup", () => {
    
    

					window.removeEventListener("mousemove", moveEvent);
					window.removeEventListener("mousedown", mousedownEvent);
					document.querySelector("body").style.cursor = "default";

					if (!moveX) {
    
    
						return;
					}
					// 把body转成canvas
					html2canvas(viewer, {
    
    
						scale: 1,
						height: (viewer.offsetHeight > 60000 ? 60000 : viewer.offsetHeight),
						width: viewer.scrollWidth,
						x: 0,
						y: document.getElementById('viewerContainer').scrollTop, // 用网页滚动的高度定位y轴顶点
						// dpi: 300,
						// allowTaint: true,
						useCORS: true,  //跨域使用
					}).then(canvas2 => {
    
    
						// document.body.append(canvas2);

						let capture_x, capture_y;
						let width = moveX;
						let height = moveY;
						if (width > 0) {
    
    
							//从左往右画
							capture_x = x + 1;
						} else {
    
    
							//从右往左画
							capture_x = x + width + 1;
						}
						if (height > 0) {
    
    
							//从上往下画
							capture_y = y + 1;
						} else {
    
    
							//从下往上画
							capture_y = y + height + 1;
						}
						printClip(canvas2, capture_x, capture_y, Math.abs(width), Math.abs(height));

						moveX = 0;
					});
				});
			};
			window.addEventListener("mousedown", mousedownEvent);
		});

Guess you like

Origin blog.csdn.net/woyebuzhidao321/article/details/131956306