在圖片上可以使用 Canvas 繪製框線,疊加在圖片上,讓圖片看起來像是有畫上線段,還可以使用 drawImage() 來裁切圖片!
這個筆記使用 HTML、CSS、JavaScript 最單純的網頁三元素來進行示範,這樣未來要插入其他地方都可以先方便理解。
目錄
Canvas 繪製框線呈現結果
呈現上會分成以下這三張圖:
- 原圖並於圖片上繪製藍色框線
- 裁切後使用 canvas 預覽
- 裁切後使用 base64 格式預覽
其中,base64 格式預覽看起來被切到,純粹是我截圖沒有截到最下面,事實上,下面兩張圖片的預覽結果都是相同的喔!
另外,這張狗狗圖片是從 Unsplash 圖庫找的,附上連結:https://unsplash.com/photos/LATYeZyw88c
或是下圖右鍵進行另存圖片也可以呦!
資料夾結構
Canvas 繪製框線 + 裁切程式碼範例
【HTML:index.html】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<h2>原圖</h2>
<div class="oriImg">
<!-- 原圖 -->
<img id="cutImg" class="cutImg" src="./img/dog.jpeg" alt="item" />
<!-- canvas 繪製區 -->
<div id="drawCanvas" class="drawCanvas">
<!-- canvas 框新增在這裡 -->
</div>
</div>
<div>
<h2>canvas 預覽</h2>
<canvas id="canvasCutBgOper"></canvas>
<br>
<h2>base64 格式預覽</h2>
<img src="" alt="" id="resultBgOper" />
</div>
<script src="./js/main.js" type="module"></script>
</body>
</html>
【CSS 檔案:style.css】
.oriImg {
position: relative;
}
.drawCanvas {
position: absolute;
top: 0;
left: 0;
}
【JS 進入點:main.js】
/* *********
主檔案
********* */
// 圖片載入的 Promise
import { imgLoad } from "./component/imgLoad.js";
import { drawCanvas } from "./component/drawCanvas.js";
import { cropImg } from "./component/cropImg.js";
function init() {
// 等圖片載入前端
imgLoad().then((res) => {
// 繪製 canvas 框
let rtnObj = drawCanvas();
// 裁切檔案並於前端顯示
cropImg(rtnObj);
});
}
init();
【圖片載入:imgLoad.js】
/* *********
圖片載入的 Promise
********* */
export function imgLoad() {
return new Promise((resolve, reject) => {
const bgImg = new Image();
bgImg.src = document.querySelector("#cutImg").getAttribute("src");
bgImg.onload = function () {
console.log("載入完成!");
resolve("Finish return");
};
});
}
【canvas 繪製框線:drawCanvas.js】
這裡要注意的是「繪製框線資料 xywh」是假資料,記得套用上你需要的位置和寬高喔!
/* *********
繪製 canvas 框線
********* */
export function drawCanvas() {
// 原圖
const cutImg = document.querySelector("#cutImg");
// 抓取原圖寬高
let originalImgW = cutImg.width;
let originalImgH = cutImg.height;
// 繪製框線資料 xywh
const objRegion = [
0.41749998927116394, 0.596666693687439, 0.5849999785423279,
0.6966666579246521,
];
// 加入 Canvas 新的節點繪製
let drawCanvas = document.querySelector("#drawCanvas");
// 欲插入的節點
let newCanvasArea = document.createElement("canvas");
newCanvasArea.setAttribute("id", `myCanvas1`);
// 插入節點
drawCanvas.appendChild(newCanvasArea);
//這一行去抓取目前要繪製的 canvas 標籤
let currentCanvas = document.getElementById(`myCanvas1`);
//讓 canvas 的高度和寬度等於你預期的畫布
currentCanvas.height = originalImgH;
currentCanvas.width = originalImgW;
// 找物件計算公式,算出左上和右下的點,乘以圖片寬或高
let x1 = (objRegion[0] - objRegion[2] / 2) * originalImgW;
let y1 = (objRegion[1] - objRegion[3] / 2) * originalImgH;
let x2 = (objRegion[0] + objRegion[2] / 2) * originalImgW;
let y2 = (objRegion[1] + objRegion[3] / 2) * originalImgH;
// 算出寬和高
let calc_w = x2 - x1;
let calc_h = y2 - y1;
// 運算後起始點座標 x1, y1, x2, y2:", x1, y1, x2, y2
// 運算後繪製出該物件(人物)的寬高:", calc_w, calc_h
// 指定繪圖方式
let ctx = currentCanvas.getContext("2d");
// 宣告使用
ctx.beginPath();
// 線段寬度
ctx.lineWidth = 3;
// 線段顏色
ctx.strokeStyle = "#3399FF";
// 使用rect(x,y,w,h)繪製四角形
ctx.rect(x1, y1, calc_w, calc_h);
// 繪製相連點的線
ctx.stroke();
// 回傳座標和寬高
let rtnObj = {
x1,
y1,
calc_w,
calc_h,
};
return rtnObj;
}
【裁切檔案並於前端顯示:cropImg.js】
/* *********
裁切檔案並於前端顯示
********* */
export function cropImg(rtnObj) {
return new Promise((resolve, reject) => {
// 預計裁切後的 canvas 圖片,顯示在畫面上
let afterCropCanvas = document.querySelector("#canvasCutBgOper");
// 預覽的寬高跟裁切的寬高相同
afterCropCanvas.width = rtnObj.calc_w;
afterCropCanvas.height = rtnObj.calc_h;
// 繪製裁切
let ctx = afterCropCanvas.getContext("2d");
// 創建 Image
let drawCropImg = new Image();
drawCropImg.src = "../img/dog.jpeg";
// 完成載入時
drawCropImg.onload = async function () {
// 使用 drawImage 裁切圖片
// 參數依序是 drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
// 參數依序是 drawImage(圖片網址, sx 裁切圖片起點, sy 裁切圖片起點, sWidth 裁切寬, sHeight 裁切高, dx 繪製起點, dy 繪製起點, dWidth 調整後的圖片寬, dHeight 調整後的圖片寬)
ctx.drawImage(
drawCropImg,
rtnObj.x1,
rtnObj.y1,
rtnObj.calc_w,
rtnObj.calc_h,
0,
0,
rtnObj.calc_w,
rtnObj.calc_h
);
// 也可以用 base64 格式顯示在 img 標籤上,作法如下:
// 裁切後的圖片,轉換成 data: 加上 MIME TYPE 等編碼及資料,這可以直接放在 src 顯示在畫面
let imgbase64 = afterCropCanvas.toDataURL("image/jpg");
// 裁切後的圖片顯示在畫面 img 標籤
document.querySelector("#resultBgOper").src = imgbase64;
resolve("finish");
};
});
}
總結
以上就是 Canvas 繪製框線、裁切檔案的功能實作囉!
延伸閱讀: