欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS使用canvas實現(xiàn)基本的截圖功能

 更新時間:2023年08月09日 10:03:22   作者:寄給江南  
這篇文章主要給大家介紹了使用JS中的canvas實現(xiàn)基本的截圖功能,文中有詳細(xì)的實現(xiàn)思路和實現(xiàn)過程,文章通過代碼示例講解的非常詳細(xì),很感興趣的同學(xué)可以參考一下

思路分析

在開始動手之前,分析一下整個功能的實現(xiàn)過程:

  • 根據(jù)圖片大小創(chuàng)建 canvas1 畫布,并將原圖片直接定位在 canvas1 上;

  • 在畫布上添加一個蒙層,以區(qū)分當(dāng)前 canvas 圖像是被裁剪的原圖像;

  • 在蒙層上方,對裁剪區(qū)域(鼠標(biāo)移動形成的矩形范圍)再次進(jìn)行圖像繪制;

  • 獲取裁剪區(qū)域的數(shù)據(jù),并將該數(shù)據(jù)定位到另一個 canvas 畫布上。

實現(xiàn)過程

準(zhǔn)備工作

首先,編寫所需的 HTML 結(jié)構(gòu)并獲取對應(yīng)元素。

<body>
  <!-- 上傳文件 -->
  <input type="file" id="imageFile" accept="image/*">
  <!-- 保存被裁剪的原圖像,初始樣式需要設(shè)置 display: none -->
  <div class="canvasContainer1">
    <canvas id="canvas1"></canvas>
  </div>
  <!-- 保存裁剪區(qū)域的圖像,初始樣式需要設(shè)置 display: none -->
  <div class="canvasContainer2">
    <canvas id="canvas2"></canvas>
  </div>
</body>
<script>
const imageFile = document.querySelector('#imageFile');
const canvasContainer1 = document.querySelector('.canvasContainer1');
const canvasContainer2 = document.querySelector('.canvasContainer2');
const canvas1 = document.querySelector('#canvas1');
const canvas2 = document.querySelector('#canvas2');
const ctx = canvas1.getContext('2d');
const ctx2 = canvas2.getContext('2d');
const imageBox = new Image(); // 創(chuàng)建一個存放圖片的容器
</script>

繪制原圖像

我們需要監(jiān)聽 input 元素的 change 事件,以獲取上傳圖片的相關(guān)參數(shù),這里主要是為了獲取圖片的寬度和高度。

我們創(chuàng)建一個 FileReader() 對象并監(jiān)聽其 load 事件。load 事件在讀取操作成功后立刻執(zhí)行,在這個方法中我們就可以獲取圖片的寬高。

function init() {
  imageFile.addEventListener('change', handleFileChange, false); // 監(jiān)聽圖片上傳事件。
}
function handleFileChange(e) {
  const imgFile = e.target.files[0]; // 獲取上傳的圖片對象。
  const reader = new FileReader();
  reader.onload = function(e) {
    const imgSrc = e.target.result; // 圖片文件的 base64 編碼格式。
    imageBox.src = imgSrc; // 把圖片放入 img 容器。
    // 等圖片加載完成后,獲取圖片的寬高。
    imageBox.onload = function () {
      const imgWidth = this.width, imgHeight = this.height;
      console.log(imgWidth, imgHeight);
    }
  }
  if (imgFile) {
    reader.readAsDataURL(imgFile); // 讀取圖片文件,讀取完成才能獲取 result 屬性。
  }
}
init();

此時還沒有圖片,我們創(chuàng)建一個自適應(yīng)圖片大小的 canvas1 畫布,并使用 drawImage() 方法將上傳的圖片直接定位到 canvas1 當(dāng)中。

function handleFileChange(e) {
  const imgFile = e.target.files[0]; // 獲取上傳的圖片對象。
  const reader = new FileReader();
  reader.onload = function (e) {
    const imgSrc = e.target.result; // 圖片的 base64 編碼。
    imageBox.src = imgSrc; // 把上傳的圖像放入 img 容器。
    // 圖片加載完畢后執(zhí)行
    imageBox.onload = function () {
      // 獲取圖片的寬高。
      const imgWidth = this.width, imgHeight = this.height;
      console.log(imgWidth, imgHeight);
      // 創(chuàng)建 canvas 畫布并繪制圖片。
      generateCanvas(canvasContainer1, canvas1, imgWidth, imgHeight);
      ctx.drawImage(imageBox, 0, 0, imgWidth, imgHeight);
    }
  }
  if (imgFile) {
    reader.readAsDataURL(imgFile); // 將當(dāng)前file讀取成DataURL
  }
}
// 根據(jù) width 和 height 創(chuàng)建 canvas 畫布。
function generateCanvas(container, canvas, width, height) {
  container.width = width + 'px';
  container.height = height + 'px';
  canvas.width = width;
  canvas.height = height;
  container.style.display = 'block'; // 顯示 canvas 區(qū)域。
}

可以看到原圖像已經(jīng)成功被繪制,接下來就可以開始動態(tài)繪制截圖區(qū)域了。

繪制截圖區(qū)域

在這個過程中,我們需要分別監(jiān)聽 imageBox 容器(原圖像)上的 mousedownmousemovemouseup 事件,這些事件的作用如下:

  • mousedown 事件:記錄開始截圖的位置,并開始監(jiān)聽 mousemovemouseup 事件。
  • mousemove 事件:監(jiān)聽鼠標(biāo)的偏移量,以計算裁剪區(qū)域的寬度和高度。
  • mouseup 事件:截圖結(jié)束,注銷監(jiān)聽 mousedownmousemove 事件,并繪制裁剪區(qū)域。
let startPosition = []; // 記錄鼠標(biāo)點擊(開始截圖)的位置。
let screenshotData = []; // 保存截取部分的相關(guān)信息。
function init() {
  // 監(jiān)聽鼠標(biāo)點擊事件。
  canvas1.addEventListener('mousedown', handleMouseDown, false);
}
// 記錄鼠標(biāo)點擊(開始截圖)的位置,并監(jiān)聽相關(guān)事件。
function handleMouseDown(e) {
  startPosition = [e.offsetX, e.offsetY];
  canvas1.addEventListener('mousemove', handleMouseMove, false);
  canvas1.addEventListener('mouseup', handleMouseUp, false);
}
// 監(jiān)聽鼠標(biāo)的偏移量,以計算裁剪區(qū)域的寬度和高度。
function handleMouseMove(e) {
  // 獲取裁剪區(qū)域的寬度和高度。
  const { offsetX, offsetY } = e;
  const [startX, startY] = startPosition;
  const [rectWidth, rectHeight] = [offsetX - startX, offsetY - startY];
  console.log('rect', rectWidth, rectHeight);
  // 保存裁剪區(qū)域的相關(guān)信息。
  screenshotData = [startX, startY, rectWidth, rectHeight];
}
// 注銷監(jiān)聽事件等后續(xù)操作。
function handleMouseUp() {
  canvas1.removeEventListener('mousemove', handleMouseMove, false);
  canvas1.removeEventListener('mouseup', handleMouseUp, false);
}

在 handleMouseMove 函數(shù)中,我們已經(jīng)獲取了裁剪區(qū)域的寬高,也就是生成截圖的寬高。

接下來,我們需要在原圖像上展示出我們所裁剪的區(qū)域,也就是這個效果:

可以看到,原圖像的上方、裁剪區(qū)域下方會覆蓋一層半透明黑色蒙層,它的作用是區(qū)分原圖層和裁剪部分圖層。所以我們需要在繪制截圖區(qū)域之前,添加一層蒙層。

注意,在已有內(nèi)容的 canvas 畫布上進(jìn)行再次繪制之前,需要先清除整個畫布的內(nèi)容。 這里通過 clearRect() 方法清除 canvas1 畫布上的所有內(nèi)容,并添加蒙層。

我們繼續(xù)來補(bǔ)充 handleMouseMovehandleMouseUp 函數(shù)中的邏輯:

const MASKER_OPACITY = 0.4;
function handleMouseMove(e) {
  // 獲取裁剪區(qū)域的寬度和高度。
  const { offsetX, offsetY } = e;
  const [startX, startY] = startPosition;
  const [rectWidth, rectHeight] = [offsetX - startX, offsetY - startY];
  console.log('rect', rectWidth, rectHeight);
  // 保存裁剪區(qū)域的相關(guān)信息。
  screenshotData = [startX, startY, rectWidth, rectHeight];
  // 再次繪制前,清理 canvas1 畫布上的內(nèi)容。
  const { width, height } = canvas1;
  ctx.clearRect(0, 0, width, height);
  // 在 canvas1 畫布上繪制蒙層。
  drawImageMasker(0, 0, width, height, MASKER_OPACITY);
  // 繪制截圖區(qū)域。
  drawScreenShot(width, height, rectWidth, rectHeight);
}
// ...
// 繪制圖片蒙層,填充范圍和顏色,以便區(qū)分原圖層和裁剪部分圖層。
function drawImageMasker(x, y, width, height, opacity) {
  ctx.fillStyle = `rgba(0, 0, 0, ${opacity})`;
  ctx.fillRect(0, 0, width, height);
}
// 繪制裁剪的矩形區(qū)域。
function drawScreenShot(canWidth, canHeight, rectWidth, rectHeight) {
  // 在源圖像外繪制新圖像,只有源圖像外的目標(biāo)圖像部分會被顯示,源圖像是透明的。
  ctx.globalCompositeOperation = 'destination-out';
  ctx.fillStyle = '#2c2c2c';
  ctx.fillRect(...startPosition, rectWidth, rectHeight);
  // 在現(xiàn)有畫布上繪制新的圖形。
  ctx.globalCompositeOperation = 'destination-over';
  ctx.drawImage(imageBox, 0, 0, canWidth, canHeight, 0, 0, canWidth, canHeight);
}

然后,當(dāng)我們放開鼠標(biāo)(結(jié)束截圖動作)時,除了注銷對 mousedownmousemove 事件的監(jiān)聽,還需要將所得的裁剪區(qū)域的圖像放入另一個 canvas 中。

在繪制新圖像的過程中,我們需要使用以下方法:

  • getImageData():讀取 canvas 上的內(nèi)容,返回一個 ImageData 對象,包含了每個像素的信息。
  • putImageData():將 ImagaData 對象的數(shù)據(jù)放入 canvas 中,覆蓋 canvas 中的已有圖像。
function handleMouseUp() {
  canvas1.removeEventListener('mousemove', handleMouseMove, false);
  canvas1.removeEventListener('mouseup', handleMouseUp, false);
  // 開始繪制截圖區(qū)域圖片。
  drawScreenshotImage(screenshotData);
  // 如果裁剪得到新圖像后,不希望保留原圖像,可以設(shè)置以下屬性。
  // canvasContainer1.style.display = 'none';
}
// 在新容器 canvas2 上繪制新圖像。
function drawScreenshotImage(screenshotData) {
  // 獲取 canvas1 的數(shù)據(jù)。
  const data = ctx.getImageData(...screenshotData);
  // 創(chuàng)建 canvas2 畫布。
  generateCanvas(canvasContainer2, canvas2, screenshotData[2], screenshotData[3]);
  // 每次繪制前,都先進(jìn)行清除操作。
  ctx2.clearRect(...screenshotData);
  // 將 canvas1 的數(shù)據(jù)放入 canvas2 中。
  ctx2.putImageData(data, 0, 0);
}

經(jīng)過以上步驟,就可以實現(xiàn)我們所需的效果

總結(jié)

對于 canvas 的使用比較少,所以想記錄一下自己的使用過程。

如果本文中出現(xiàn)了什么錯誤或者有什么建議,歡迎大家指正~

以上就是JS使用canvas實現(xiàn)基本的截圖功能的詳細(xì)內(nèi)容,更多關(guān)于JS canvas截圖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論