# 使用Canvas怎么繪制一個圖片小程序
Canvas是HTML5提供的強大繪圖API,可以用于開發各種圖形處理小程序。本文將詳細介紹如何從零開始構建一個基于Canvas的圖片編輯小程序,涵蓋基礎繪制、圖片處理、交互功能等完整實現流程。
## 一、Canvas基礎準備
### 1.1 HTML結構搭建
首先創建基本的HTML結構,包含Canvas元素和操作按鈕:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Canvas圖片編輯器</title>
<style>
#canvas-container {
display: flex;
justify-content: center;
margin: 20px 0;
}
#toolbar {
display: flex;
gap: 10px;
padding: 10px;
justify-content: center;
}
button {
padding: 8px 15px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="toolbar">
<input type="file" id="upload" accept="image/*">
<button id="grayscale">灰度化</button>
<button id="invert">反色</button>
<button id="reset">重置</button>
</div>
<div id="canvas-container">
<canvas id="imageCanvas" width="800" height="600"></canvas>
</div>
<script src="app.js"></script>
</body>
</html>
在app.js中獲取Canvas上下文:
const canvas = document.getElementById('imageCanvas');
const ctx = canvas.getContext('2d');
let originalImageData = null;
// 初始化白色背景
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
document.getElementById('upload').addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(event) {
const img = new Image();
img.onload = function() {
// 計算適應Canvas的尺寸
const scale = Math.min(
canvas.width / img.width,
canvas.height / img.height
);
const width = img.width * scale;
const height = img.height * scale;
// 居中繪制
const x = (canvas.width - width) / 2;
const y = (canvas.height - height) / 2;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, x, y, width, height);
// 保存原始圖像數據
originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
});
上述代碼中的縮放邏輯使用了等比縮放算法:
const scale = Math.min(
canvas.width / img.width,
canvas.height / img.height
);
這種算法可以保證: 1. 圖片完整顯示不裁剪 2. 保持原始寬高比 3. 適應Canvas容器大小
document.getElementById('grayscale').addEventListener('click', function() {
if (!originalImageData) return;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // R
data[i + 1] = avg; // G
data[i + 2] = avg; // B
}
ctx.putImageData(imageData, 0, 0);
});
document.getElementById('invert').addEventListener('click', function() {
if (!originalImageData) return;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // R
data[i + 1] = 255 - data[i + 1]; // G
data[i + 2] = 255 - data[i + 2]; // B
}
ctx.putImageData(imageData, 0, 0);
});
document.getElementById('reset').addEventListener('click', function() {
if (originalImageData) {
ctx.putImageData(originalImageData, 0, 0);
}
});
讓用戶可以在圖片上繪制標記:
let isDrawing = false;
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
function startDrawing(e) {
isDrawing = true;
draw(e);
}
function draw(e) {
if (!isDrawing) return;
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.strokeStyle = '#ff0000';
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
}
function stopDrawing() {
isDrawing = false;
ctx.beginPath();
}
實現更多圖片濾鏡效果:
// 復古濾鏡
function applySepia(imageData) {
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
data[i] = Math.min(255, (r * 0.393) + (g * 0.769) + (b * 0.189));
data[i + 1] = Math.min(255, (r * 0.349) + (g * 0.686) + (b * 0.168));
data[i + 2] = Math.min(255, (r * 0.272) + (g * 0.534) + (b * 0.131));
}
return imageData;
}
// 使用示例
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
ctx.putImageData(applySepia(imageData), 0, 0);
對于復雜操作,使用離屏Canvas提升性能:
const offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
const offscreenCtx = offscreenCanvas.getContext('2d');
// 處理時先在離屏Canvas操作
offscreenCtx.drawImage(canvas, 0, 0);
// ...執行各種處理...
ctx.drawImage(offscreenCanvas, 0, 0);
實現簡單的操作歷史記錄:
const history = [];
const MAX_HISTORY = 10;
function saveState() {
if (history.length >= MAX_HISTORY) {
history.shift();
}
history.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
}
// 每次操作前調用saveState()
// 撤銷按鈕實現
document.getElementById('undo').addEventListener('click', function() {
if (history.length > 0) {
ctx.putImageData(history.pop(), 0, 0);
}
});
將上述功能整合,添加更多實用功能:
// 添加文字功能
document.getElementById('addText').addEventListener('click', function() {
const text = prompt('輸入要添加的文字:');
if (text) {
ctx.font = '30px Arial';
ctx.fillStyle = '#000000';
ctx.fillText(text, 50, 50);
saveState();
}
});
// 保存圖片
document.getElementById('save').addEventListener('click', function() {
const link = document.createElement('a');
link.download = 'edited-image.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
使Canvas適應不同屏幕尺寸:
function resizeCanvas() {
const container = document.getElementById('canvas-container');
canvas.width = container.clientWidth - 40;
canvas.height = window.innerHeight * 0.7;
if (originalImageData) {
ctx.putImageData(originalImageData, 0, 0);
}
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
本文詳細介紹了如何使用Canvas API開發一個功能完整的圖片處理小程序,包括:
通過這個項目,您可以掌握Canvas的核心API使用,理解像素級操作原理,并能夠擴展到更復雜的圖形應用開發中。Canvas的強大之處在于其靈活性,您可以根據需求繼續添加更多高級功能,如圖層混合、高級濾鏡、機器學習風格遷移等復雜效果。 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。