# 前端图片盖章工具设计方案

下面是一

By 17128289777, 26 July, 2025
角色
assistant
content

# 前端图片盖章工具设计方案

下面是一个精简而功能完整的前端图片盖章工具实现方案:

## 核心功能实现代码 (HTML/CSS/JS)

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能图片盖章工具</title>
<style>
:root {
--primary: #4361ee;
--secondary: #3f37c9;
--light: #f8f9fa;
--dark: #212529;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f7fb;
color: var(--dark);
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
padding: 24px;
}
h1 {
color: var(--primary);
margin-top: 0;
text-align: center;
}
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
.btn {
background: var(--primary);
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.btn:hover {
background: var(--secondary);
transform: translateY(-1px);
}
.btn-secondary {
background: #6c757d;
}
.canvas-container {
position: relative;
margin: 0 auto;
border: 1px dashed #ddd;
border-radius: 8px;
overflow: hidden;
background-color: #f9f9f9;
min-height: 400px;
}
#mainCanvas {
display: block;
max-width: 100%;
}
.stamp-controls {
display: flex;
gap: 12px;
margin-top: 16px;
flex-wrap: wrap;
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
background: #f8f9fa;
padding: 12px;
border-radius: 8px;
flex-grow: 1;
}
label {
font-size: 14px;
font-weight: 500;
}
input[type="range"] {
width: 100%;
}
.file-input {
display: none;
}
.preview-stamp {
width: 100px;
height: 100px;
object-fit: contain;
border: 1px solid #eee;
border-radius: 4px;
margin-top: 8px;
}
</style>
</head>
<body>
<div class="container">
<h1>智能图片盖章工具</h1>

<div class="toolbar">
<button id="uploadImage" class="btn">上传图片</button>
<button id="uploadStamp" class="btn">上传印章</button>
<button id="addRegularStamp" class="btn">添加普通章</button>
<button id="addSeamStamp" class="btn">添加骑缝章</button>
<button id="download" class="btn btn-secondary">下载图片</button>
<button id="reset" class="btn btn-secondary">重置</button>
</div>

<div class="canvas-container">
<canvas id="mainCanvas"></canvas>
</div>

<div class="stamp-controls">
<div class="control-group">
<label for="opacity">印章透明度</label>
<input type="range" id="opacity" min="0" max="1" step="0.1" value="0.8">
</div>
<div class="control-group">
<label for="blendMode">混合模式</label>
<select id="blendMode" class="btn">
<option value="source-over">正常</option>
<option value="multiply">正片叠底</option>
<option value="screen">滤色</option>
<option value="overlay">叠加</option>
</select>
</div>
<div class="control-group">
<label>当前印章</label>
<img id="previewStamp" src="" class="preview-stamp" alt="印章预览">
</div>
</div>
</div>

<input type="file" id="imageInput" class="file-input" accept="image/*">
<input type="file" id="stampInput" class="file-input" accept="image/*">

<script>
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('mainCanvas');
const ctx = canvas.getContext('2d');
const imageInput = document.getElementById('imageInput');
const stampInput = document.getElementById('stampInput');
const uploadImageBtn = document.getElementById('uploadImage');
const uploadStampBtn = document.getElementById('uploadStamp');
const addRegularStampBtn = document.getElementById('addRegularStamp');
const addSeamStampBtn = document.getElementById('addSeamStamp');
const downloadBtn = document.getElementById('download');
const resetBtn = document.getElementById('reset');
const opacityControl = document.getElementById('opacity');
const blendModeControl = document.getElementById('blendMode');
const previewStamp = document.getElementById('previewStamp');

let currentImage = null;
let currentStamp = null;
let activeStamp = null;
let isDragging = false;
let dragStartX, dragStartY;
let stampX, stampY;

// 初始化画布
function initCanvas() {
canvas.width = canvas.parentElement.clientWidth;
canvas.height = 500;
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = 'center';
ctx.fillStyle = '#999';
ctx.font = '20px Arial';
ctx.fillText('请上传图片或添加印章', canvas.width/2, canvas.height/2);
}

// 上传图片
uploadImageBtn.addEventListener('click', function() {
imageInput.click();
});

imageInput.addEventListener('change', function(e) {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function(event) {
const img = new Image();
img.onload = function() {
currentImage = img;
drawCanvas();
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
}
});

// 上传印章
uploadStampBtn.addEventListener('click', function() {
stampInput.click();
});

stampInput.addEventListener('change', function(e) {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function(event) {
const img = new Image();
img.onload = function() {
currentStamp = img;
previewStamp.src = event.target.result;
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
}
});

// 添加普通印章
addRegularStampBtn.addEventListener('click', function() {
if (!currentStamp) return alert('请先上传印章');

activeStamp = {
type: 'regular',
img: currentStamp,
x: canvas.width/2 - currentStamp.width/2,
y: canvas.height/2 - currentStamp.height/2,
width: currentStamp.width,
height: currentStamp.height
};

drawCanvas();
});

// 添加骑缝章
addSeamStampBtn.addEventListener('click', function() {
if (!currentImage) return alert('请先上传图片');
if (!currentStamp) return alert('请先上传印章');

const stampWidth = Math.min(currentStamp.width, 200);
const stampHeight = Math.min(currentStamp.height, 200);

activeStamp = {
type: 'seam',
img: currentStamp,
x: canvas.width/2 - stampWidth/2,
y: canvas.height/2 - stampHeight/2,
width: stampWidth,
height: stampHeight
};

drawCanvas();
});

// 绘制画布
function drawCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

// 绘制背景图片
if (currentImage) {
// 计算图片尺寸以保持比例
const ratio = Math.min(
canvas.width / currentImage.width,
canvas.height / currentImage.height
);
const imgWidth = currentImage.width * ratio;
const imgHeight = currentImage.height * ratio;
const imgX = (canvas.width - imgWidth) / 2;
const imgY = (canvas.height - imgHeight) / 2;

ctx.drawImage(currentImage, imgX, imgY, imgWidth, imgHeight);

// 存储图片位置信息用于骑缝章
if (activeStamp && activeStamp.type === 'seam') {
activeStamp.imageX = imgX;
activeStamp.imageY = imgY;
activeStamp.imageWidth = imgWidth;
activeStamp.imageHeight = imgHeight;
}
} else {
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}

// 绘制印章
if (activeStamp) {
ctx.globalAlpha = opacityControl.value;
ctx.globalCompositeOperation = blendModeControl.value;

if (activeStamp.type === 'regular') {
// 普通印章
ctx.drawImage(
activeStamp.img,
activeStamp.x,
activeStamp.y,
activeStamp.width,
activeStamp.height
);
} else if (activeStamp.type === 'seam') {
// 骑缝章 - 绘制两半
const clipX = activeStamp.imageX + activeStamp.imageWidth/2;

// 左半部分
ctx.save();
ctx.beginPath();
ctx.rect(
activeStamp.imageX,
activeStamp.imageY,
activeStamp.imageWidth/2,
activeStamp.imageHeight
);
ctx.clip();
ctx.drawImage(
activeStamp.img,
activeStamp.x,
activeStamp.y,
activeStamp.width,
activeStamp.height
);
ctx.restore();

// 右半部分
ctx.save();
ctx.beginPath();
ctx.rect(
clipX,
activeStamp.imageY,
activeStamp.imageWidth/2,
activeStamp.imageHeight
);
ctx.clip();
ctx.drawImage(
activeStamp.img,
activeStamp.x,
activeStamp.y,
activeStamp.width,
activeStamp.height
);
ctx.restore();
}

// 重置混合模式
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
}
}

// 下载图片
downloadBtn.addEventListener('click', function() {
if (!currentImage && !activeStamp) return alert('没有可下载的内容');

const link = document.createElement('a');
link.download = 'stamped-image.png';
link.href = canvas.toDataURL('image/png');
link.click();
});

// 重置
resetBtn.addEventListener('click', function() {
currentImage = null;
currentStamp = null;
activeStamp = null;
previewStamp.src = '';
initCanvas();
});

// 拖动印章
canvas.addEventListener('mousedown', function(e) {
if (!activeStamp) return;

const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;

// 检查是否点击在印章上
if (x >= activeStamp.x && x <= activeStamp.x + activeStamp.width &&
y >= activeStamp.y && y <= activeStamp.y + activeStamp.height) {
isDragging = true;
dragStartX = x - activeStamp.x;
dragStartY = y - activeStamp.y;
}
});

canvas.addEventListener('mousemove', function(e) {
if (!isDragging || !activeStamp) return;

const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;

activeStamp.x = x - dragStartX;
activeStamp.y = y - dragStartY;

drawCanvas();
});

canvas.addEventListener('mouseup', function() {
isDragging = false;
});

canvas.addEventListener('mouseleave', function() {
isDragging = false;
});

// 控制调整
opacityControl.addEventListener('input', drawCanvas);
blendModeControl.addEventListener('change', drawCanvas);

// 初始化
initCanvas();
});
</script>
</body>
</html>
```

## 功能特点说明

1. **核心功能实现**:
- 图片上传与显示
- 印章上传与预览
- 普通印章添加与拖动
- 骑缝章实现(自动分割到图片两侧)
- 混合模式选择(正常/正片叠底/滤色/叠加)
- 透明度调节
- 图片下载功能

2. **精简设计理念**:
- 单HTML文件包含所有功能
- 纯前端实现,无需后端
- 使用Canvas API进行图像处理
- 采用现代CSS变量和flex布局

3. **现代UI设计**:
- 干净简洁的界面
- 响应式布局
- 平滑的交互效果
- 直观的操作流程

4. **优化用户体验**:
- 印章拖动时的实时预览
- 操作按钮的状态反馈
- 错误预防提示
- 直观的缩略图预览

## 扩展建议

如需进一步增强功能,可以考虑:
1. 添加多种预设印章样式
2. 实现印章旋转功能
3. 添加撤销/重做操作
4. 支持多印章管理
5. 增加图片基础编辑功能(裁剪、旋转等)

这个实现保持了代码精简(全部在一个HTML文件中),同时提供了完整的基本功能,界面美观现代,适合大部分盖章需求。

total_tokens
3757