项目简介
这是一个基于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();
}
使用说明
1.上传图片:点击"上传图片"按钮选择本地图片
2.基础编辑:
- 使用画笔工具进行绘制
- 使用橡皮擦工具擦除内容
- 调节亮度和对比度滑块修改图片效果
3.撤销/重做:使用对应按钮进行操作历史管理
4.保存图片:点击"保存"按钮将结果保存为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>
到此这篇关于基于javascript实现网页版的绘图板的文章就介绍到这了,更多相关javascript绘图板内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论