项目简介
这是一个基于HTML5 Canvas和jQuery实现的简单网页版绘图编辑器。提供了基础的图片编辑功能,包括画笔工具、橡皮擦、亮度/对比度调节等功能。可以用于简单的图片编辑和绘图需求。
主要功能
1. 基础绘图工具
- 画笔工具:支持自定义颜色和大小
- 橡皮擦工具:支持自定义大小
- 撤销/重做:支持多步操作历史记录
2. 图片处理
- 图片上传:支持上传本地图片
- 图片调整:支持亮度和对比度调节
- 图片保存:可将编辑后的图片保存到本地
技术实现要点
1. 画布初始化
const canvas = $('#imageCanvas')[0];
const ctx = canvas.getContext('2d');
使用HTML5 Canvas作为绘图基础,默认设置白色背景。
2. 绘图实现
绘图功能通过监听鼠标事件实现:
mousedown
:开始绘制mousemove
:持续绘制mouseup/mouseleave
:结束绘制
关键代码:
function startDrawing(e) {
isDrawing = true;
ctx.beginPath();
if (currentTool === 'eraser') {
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
} else {
ctx.globalCompositeOperation = 'source-over';
}
ctx.moveTo(e.offsetX, e.offsetY);
}
3. 橡皮擦实现
橡皮擦通过设置 Canvas 的 globalCompositeOperation
属性为 ‘destination-out’ 来实现透明擦除效果:
if (currentTool === 'eraser') {
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
}
4. 图片处理
图片上传后会自动调整大小以适应画布,保持原始比例:
const scale = Math.min(canvas.width / img.width, canvas.height / img.height);
const x = (canvas.width - img.width * scale) / 2;
const y = (canvas.height - img.height * scale) / 2;
5. 亮度和对比度调节
使用 Canvas 的 filter 属性实现:
ctx.filter = `brightness(${brightness}%) contrast(${contrast}%)`;
6. 撤销/重做功能
通过保存画布状态实现:
function saveState() {
undoStack.push(canvas.toDataURL());
redoStack = [];
updateUndoRedoButtons();
}
使用说明
- 上传图片:点击"上传图片"按钮选择本地图片
- 基础编辑:
- 使用画笔工具进行绘制
- 使用橡皮擦工具擦除内容
- 调节亮度和对比度滑块修改图片效果
- 撤销/重做:使用对应按钮进行操作历史管理
- 保存图片:点击"保存"按钮将结果保存为PNG格式
技术依赖
- HTML5 Canvas
- jQuery 3.7.1
- 现代浏览器(支持ES6+)
改进方向
1. 功能扩展
- 添加图片旋转/翻转功能
- 实现图片裁剪功能
- 添加更多滤镜效果
- 实现图层功能
2. 用户体验优化
- 添加快捷键支持
- 优化工具切换交互
- 添加操作提示
- 完善错误处理
3. 性能优化
- 优化大图片处理
- 改进撤销/重做机制
- 添加操作状态缓存
- 优化Canvas渲染性能
注意事项
- 图片上传大小没有限制,但建议不要超过5MB
- 保存的图片格式为PNG,支持透明度
- 浏览器需要支持Canvas的相关API
完整代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网页版图片编辑器</title>
<!-- 引入 jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f0f0f0;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.toolbar {
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.toolbar button {
padding: 8px 15px;
margin: 0 5px;
border: 1px solid #ddd;
border-radius: 4px;
background: #fff;
cursor: pointer;
transition: all 0.3s ease;
}
.toolbar button:hover {
background: #f5f5f5;
}
.toolbar button.active {
background: #e0e0e0;
}
.canvas-container {
position: relative;
margin: 20px 0;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#imageCanvas {
border: 1px solid #ddd;
margin: 0 auto;
display: block;
}
.controls {
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-top: 20px;
}
.control-group {
margin: 10px 0;
}
.control-group label {
display: block;
margin-bottom: 5px;
}
input[type="range"] {
width: 200px;
}
input[type="color"] {
width: 50px;
height: 30px;
padding: 0;
border: none;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="toolbar">
<input type="file" id="imageInput" class="hidden" accept="image/*">
<button id="uploadBtn">上传图片</button>
<button id="undoBtn" disabled>撤销</button>
<button id="redoBtn" disabled>重做</button>
<button id="saveBtn" disabled>保存</button>
<button id="brushBtn">画笔</button>
<button id="eraserBtn">橡皮擦</button>
</div>
<div class="canvas-container">
<canvas id="imageCanvas" width="800" height="600"></canvas>
</div>
<div class="controls">
<div class="control-group">
<label for="brightnessRange">亮度:</label>
<input type="range" id="brightnessRange" min="0" max="200" value="100">
<span id="brightnessValue">100%</span>
</div>
<div class="control-group">
<label for="contrastRange">对比度:</label>
<input type="range" id="contrastRange" min="0" max="200" value="100">
<span id="contrastValue">100%</span>
</div>
<div class="control-group">
<label for="brushSize">画笔大小:</label>
<input type="range" id="brushSize" min="1" max="50" value="5">
<span id="brushSizeValue">5px</span>
</div>
<div class="control-group">
<label for="brushColor">画笔颜色:</label>
<input type="color" id="brushColor" value="#000000">
</div>
</div>
</div>
<script>
$(document).ready(function() {
const canvas = $('#imageCanvas')[0];
const ctx = canvas.getContext('2d');
let isDrawing = false;
let currentTool = 'brush';
let originalImage = null;
let undoStack = [];
let redoStack = [];
// 初始化画布,设置白色背景
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
saveState();
// 工具选择
$('#brushBtn').click(function() {
currentTool = 'brush';
$(this).addClass('active');
$('#eraserBtn').removeClass('active');
});
$('#eraserBtn').click(function() {
currentTool = 'eraser';
$(this).addClass('active');
$('#brushBtn').removeClass('active');
});
// 绘图功能
function startDrawing(e) {
isDrawing = true;
ctx.beginPath();
if (currentTool === 'eraser') {
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
} else {
ctx.globalCompositeOperation = 'source-over';
}
ctx.moveTo(e.offsetX, e.offsetY);
}
function draw(e) {
if (!isDrawing) return;
if (currentTool === 'eraser') {
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
} else {
ctx.globalCompositeOperation = 'source-over';
}
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
if (currentTool === 'eraser') {
ctx.restore();
}
}
function stopDrawing() {
if (isDrawing) {
isDrawing = false;
ctx.closePath();
if (currentTool === 'eraser') {
ctx.restore();
}
saveState();
}
}
$('#imageCanvas').mousedown(startDrawing)
.mousemove(draw)
.mouseup(stopDrawing)
.mouseleave(stopDrawing);
// 画笔控制
$('#brushColor').change(function() {
ctx.strokeStyle = $(this).val();
});
$('#brushSize').on('input', function() {
const size = $(this).val();
ctx.lineWidth = size;
$('#brushSizeValue').text(size + 'px');
});
// 图片上传处理
$('#uploadBtn').click(function() {
$('#imageInput').click();
});
$('#imageInput').change(function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
const img = new Image();
img.onload = function() {
// 保持图片比例
const scale = Math.min(canvas.width / img.width, canvas.height / img.height);
const x = (canvas.width - img.width * scale) / 2;
const y = (canvas.height - img.height * scale) / 2;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
originalImage = img;
saveState();
$('#saveBtn').prop('disabled', false);
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
}
});
// 图片调整
function applyAdjustments() {
if (!originalImage) return;
const brightness = $('#brightnessRange').val();
const contrast = $('#contrastRange').val();
// 计算保持宽高比的缩放
const scale = Math.min(canvas.width / originalImage.width, canvas.height / originalImage.height);
const x = (canvas.width - originalImage.width * scale) / 2;
const y = (canvas.height - originalImage.height * scale) / 2;
ctx.filter = `brightness(${brightness}%) contrast(${contrast}%)`;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(originalImage, x, y, originalImage.width * scale, originalImage.height * scale);
ctx.filter = 'none';
saveState();
}
$('#brightnessRange, #contrastRange').on('input', function() {
const value = $(this).val();
const id = $(this).attr('id');
$(`#${id}Value`).text(value + '%');
applyAdjustments();
});
// 撤销/重做功能
function saveState() {
undoStack.push(canvas.toDataURL());
redoStack = [];
updateUndoRedoButtons();
}
function updateUndoRedoButtons() {
$('#undoBtn').prop('disabled', undoStack.length <= 1);
$('#redoBtn').prop('disabled', redoStack.length === 0);
}
$('#undoBtn').click(function() {
if (undoStack.length <= 1) return;
redoStack.push(undoStack.pop());
const lastState = undoStack[undoStack.length - 1];
loadState(lastState);
updateUndoRedoButtons();
});
$('#redoBtn').click(function() {
if (redoStack.length === 0) return;
const nextState = redoStack.pop();
undoStack.push(nextState);
loadState(nextState);
updateUndoRedoButtons();
});
function loadState(state) {
const img = new Image();
img.onload = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
};
img.src = state;
}
// 保存功能
$('#saveBtn').click(function() {
const link = document.createElement('a');
link.download = '编辑后的图片.png';
link.href = canvas.toDataURL();
link.click();
});
// 设置初始画笔属性
ctx.strokeStyle = $('#brushColor').val();
ctx.lineWidth = $('#brushSize').val();
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
});
</script>
</body>
</html>
本项目仅用于学习和参考。
标签:function,canvas,网页,img,Javascript,ctx,width,const,绘图板 From: https://blog.csdn.net/exlink2012/article/details/143370478