前言
演示网址:https://uurr.cn/myfile/page/watermark/
支持文字水印和图片水印,支持自定义水印大小,颜色,旋转方向,间距,透明度
效果
代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>水印生成器</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f9f9f9;
color: #333;
display: flex;
padding: 50px;
margin: 0;
}
.image-container {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #ccc;
background-color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-right: 50px;
}
.settings-container {
flex: 0 0 350px;
/* 允许放大,基础宽度为310px */
display: flex;
flex-direction: column;
margin-right: 50px;
}
h1 {
margin-bottom: 20px;
font-size: 24px;
text-align: center;
}
input[type="file"],
input[type="text"],
input[type="color"],
input[type="range"],
button {
padding: 6px;
margin: 6px 0;
border: 1px solid #ccc;
border-radius: 5px;
width: 50%;
font-size: 16px;
}
input[type="file"],
input[type="text"],
input[type="color"],
input[type="range"],
button {
padding: 6px;
margin: 6px 0;
border: 1px solid #ccc;
border-radius: 5px;
width: 60%;
font-size: 16px;
}
button {
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
transition: background-color 0.3s;
width: 100%;
}
button:hover {
background-color: #0056b3;
}
canvas {
max-width: 90%;
height: auto;
}
.slider-label {
margin-top:10px ;
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
</head>
<body>
<div class="image-container">
<canvas id="canvas"></canvas>
</div>
<div class="settings-container">
<h1>在线水印生成器</h1>
<div class="slider-label">
<label>选择图片</label>
<input type="file" id="imageUpload" accept="image/*" placeholder="上传主图">
</div>
<div class="slider-label">
<label>图片水印</label>
<input type="text" id="watermarkText" placeholder="输入水印文字" value="输入水印文字">
</div>
<div class="slider-label">
<span>图片水印</span>
<input type="file" id="watermarkImageUpload" accept="image/*" placeholder="上传水印图片">
</div>
<div class="slider-label">
<label for="watermarkColor">文字颜色</label>
<input type="color" id="watermarkColor" value="#ffffff">
</div>
<div class="slider-label">
<label for="watermarkSize">文字大小</label>
<input type="range" id="watermarkSize" min="1" max="100" value="20">
<span id="watermarkSizeValue">20</span>
</div>
<div class="slider-label">
<label for="spacing">文字间距</label>
<input type="range" id="spacing" min="90" max="300" value="100">
<span id="spacingValue">100</span>
</div>
<div class="slider-label">
<label for="rotation">水印角度</label>
<input type="range" id="rotation" min="0" max="360" value="310">
<span id="rotationValue">310</span>
</div>
<div class="slider-label">
<label for="opacity">水印透明</label>
<input type="range" id="opacity" min="0" max="100" value="50">
<span id="opacityValue">50</span>
</div>
<button class="save" id="saveButton">保存图片</button>
</div>
<script>
const imageUpload = document.getElementById('imageUpload');
const watermarkImageUpload = document.getElementById('watermarkImageUpload');
const watermarkText = document.getElementById('watermarkText');
const watermarkColor = document.getElementById('watermarkColor');
const watermarkSize = document.getElementById('watermarkSize');
const spacing = document.getElementById('spacing');
const rotation = document.getElementById('rotation');
const opacity = document.getElementById('opacity');
const saveButton = document.getElementById('saveButton');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let mainImage, watermarkImage;
// 初始化数值显示
const watermarkSizeValue = document.getElementById('watermarkSizeValue');
const spacingValue = document.getElementById('spacingValue');
const rotationValue = document.getElementById('rotationValue');
const opacityValue = document.getElementById('opacityValue');
imageUpload.addEventListener('change', handleImageUpload);
watermarkImageUpload.addEventListener('change', handleWatermarkImageUpload);
watermarkText.addEventListener('input', generateWatermarkedImage);
watermarkColor.addEventListener('input', generateWatermarkedImage);
watermarkSize.addEventListener('input', () => {
watermarkSizeValue.textContent = watermarkSize.value; // 更新文字大小数值
generateWatermarkedImage();
});
spacing.addEventListener('input', () => {
spacingValue.textContent = spacing.value; // 更新间距数值
generateWatermarkedImage();
});
rotation.addEventListener('input', () => {
rotationValue.textContent = rotation.value; // 更新旋转角度数值
generateWatermarkedImage();
});
opacity.addEventListener('input', () => {
opacityValue.textContent = opacity.value; // 更新透明度数值
generateWatermarkedImage();
});
saveButton.addEventListener('click', saveImage);
function handleImageUpload(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
mainImage = new Image();
mainImage.src = e.target.result;
mainImage.onload = () => {
canvas.width = mainImage.width;
canvas.height = mainImage.height;
generateWatermarkedImage();
}
}
reader.readAsDataURL(file);
}
}
function handleWatermarkImageUpload(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
watermarkImage = new Image();
watermarkImage.src = e.target.result;
watermarkImage.onload = generateWatermarkedImage; // 当图片加载完成时生成水印
}
reader.readAsDataURL(file);
}
}
function generateWatermarkedImage() {
if (!mainImage) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(mainImage, 0, 0);
const size = parseInt(watermarkSize.value);
const spacingValue = parseInt(spacing.value);
const color = watermarkColor.value;
const angle = parseInt(rotation.value) * (Math.PI / 180); // 角度转换为弧度
const alpha = parseInt(opacity.value) / 100; // 透明度转换为小数
const rows = Math.ceil(canvas.height / (size + spacingValue));
const cols = Math.ceil(canvas.width / (size + spacingValue));
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const x = j * (size + spacingValue);
const y = i * (size + spacingValue) + size; // +size 确保文字不会被遮挡
ctx.save(); // 保存当前状态
ctx.translate(x + size / 2, y - size / 2); // 移动到水印中心
ctx.rotate(angle); // 旋转
if (watermarkText.value) {
ctx.font = `${size}px Arial`;
ctx.fillStyle = color;
ctx.globalAlpha = alpha; // 设置透明度
ctx.fillText(watermarkText.value, -ctx.measureText(watermarkText.value).width / 2, 0); // 绘制文字,中心对齐
}
if (watermarkImage) {
ctx.globalAlpha = alpha; // 设置透明度
ctx.drawImage(watermarkImage, -size / 2, -size / 2, size, size); // 假设图片水印也是方形
}
ctx.restore(); // 恢复状态
}
}
ctx.globalAlpha = 1; // 重置透明度
}
function saveImage() {
const link = document.createElement('a');
link.download = 'watermarked-image.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
</script>
</body>
</html>
代码详解
HTML结构:
updateFileName()函数在用户选择文件时被调用。
input.files是一个FileList对象,包含用户选择的文件。如果用户选择了文件,就会更新的文本内容为文件名;如果没有选择文件,则保持默认提示。
评论 (0)