使用HTML结合JavaScript,可以轻松创建一个图片水印生成器,离线版本的单页面工具。该工具允许用户上传图片并添加自定义文本水印,生成带有可见标记的图像提供下载。这样,当复印件被滥用时,水印能提供所有权证明和溯源依据,有效防止非法复制和使用。
界面效果图如下:
代码部分:
html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>高级图片加水印工具</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Arial, sans-serif;
background-color: #f4f4f4;
height: 100vh;
overflow: hidden;
display: flex;
}
.container {
width: 100%;
height: 100%;
display: flex;
}
/* 图片预览区域 - 左侧 */
.preview-panel {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: #eee;
overflow: auto;
}
#canvas {
max-width: 95vw;
max-height: 95vh;
border: 1px solid #ccc;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
/* 参数控制面板 - 右侧 */
.form-panel {
width: 320px;
background-color: #fff;
padding: 20px;
border-left: 1px solid #ddd;
overflow-y: auto;
height: 100vh;
}
.form-group {
margin-bottom: 16px;
}
label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: #333;
}
input[type="text"],
input[type="number"],
input[type="range"],
input[type="file"],
select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
input[type="color"] {
width: 50px;
height: 36px;
cursor: pointer;
}
button {
width: 100%;
padding: 12px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
margin-top: 10px;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
button:hover:not(:disabled) {
background-color: #0056b3;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 4px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #007bff;
}
input:checked + .slider:before {
transform: translateX(26px);
}
.switch-label {
display: flex;
align-items: center;
gap: 10px;
}
</style>
</head>
<body>
<div class="container">
<!-- 左侧:图片预览 -->
<div class="preview-panel">
<canvas id="canvas"></canvas>
</div>
<!-- 右侧:参数面板 -->
<div class="form-panel">
<h2 style="margin-bottom: 20px; color: #333;">水印设置</h2>
<div class="form-group">
<label for="imageInput">选择图片</label>
<input type="file" id="imageInput" accept="image/*" />
</div>
<div class="form-group">
<label for="presetSelect">选择预设:</label>
<select id="presetSelect" onchange="applyPreset()">
<option value="">请选择...</option>
<!-- 预设选项将通过JavaScript动态生成 -->
</select>
</div>
<div class="form-group">
<label for="watermarkText">水印文字</label>
<input type="text" id="watermarkText" placeholder="请输入水印文字" value="复印无效" />
</div>
<div class="form-group">
<label class="switch-label">
<span>开启水印错位</span>
<label class="switch">
<input type="checkbox" id="staggeredToggle" />
<span class="slider"></span>
</label>
</label>
<small style="color: #666;">开启后奇数行和偶数行水印交错排列,防拼接</small>
</div>
<div class="form-group">
<label for="angle">倾斜角度(度)</label>
<input type="number" id="angle" min="-360" max="360" step="1" value="45" />
</div>
<div class="form-group">
<label for="color">水印颜色</label>
<input type="color" id="color" value="#FF0000" />
</div>
<div class="form-group">
<label for="fontSize">字体大小(px)</label>
<input type="number" id="fontSize" min="10" max="100" step="1" value="32" />
</div>
<div class="form-group">
<label for="fontFamily">字体</label>
<select id="fontFamily">
<option value="Arial">Arial</option>
<option value="SimHei">黑体</option>
<option value="SimSun">宋体</option>
<option value="Microsoft YaHei">微软雅黑</option>
</select>
</div>
<div class="form-group">
<label for="opacity">透明度(0.0 - 1.0)</label>
<input type="range" id="opacity" min="0" max="1" step="0.05" value="0.3" />
<span id="opacityValue" style="font-size:12px; color:#666;">0.3</span>
</div>
<div class="form-group">
<label for="horizontalSpacing">横向间距(px)</label>
<input type="number" id="horizontalSpacing" min="0" value="100" />
</div>
<div class="form-group">
<label for="verticalSpacing">纵向间距(px)</label>
<input type="number" id="verticalSpacing" min="0" value="100" />
</div>
<button id="downloadBtn" disabled>📥 下载带水印图片</button>
</div>
</div>
<script>
// 定义预设配置
const presets = [
// 综合
{ name: "租房合同使用", text: "本复印件仅用于租赁XX小区XX房使用,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "购房资格审核", text: "本件仅用于购房资格审查,不得用于其他用途。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "公司入职材料", text: "本复印件仅用于XX公司员工入职档案建立,不得外泄。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "子女入学报名", text: "本复印件仅用于XX小学2025年秋季入学报名使用,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "公积金提取", text: "本复印件仅用于住房公积金提取申请,不得挪作他用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "社保办理", text: "本件仅用于社会保险参保登记,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "医保报销", text: "本复印件仅用于医疗保险费用报销,有效期至2025年12月31日。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "签证申请", text: "本复印件仅用于申办XX国旅游签证,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "营业执照办理", text: "本件仅用于个体工商户营业执照申请,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "婚姻登记", text: "本复印件仅用于结婚登记手续,不得用于其他用途。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "银行开户", text: "本复印件仅用于在XX银行开立个人账户,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "学历认证", text: "本复印件仅用于学信网学历认证,有效期至2025年12月。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "医院住院登记", text: "本复印件仅用于XX医院住院身份核验,不得外传。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "商业保险投保", text: "本复印件仅用于重大疾病保险投保审核,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "理赔材料提交", text: "本件仅用于意外伤害保险理赔,不得用于其他索赔。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "商标注册材料", text: "本复印件仅用于个体工商户商标注册申请,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "公司股东变更", text: "本件仅用于XX有限公司股东信息变更备案,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "招投标文件附件", text: "本复印件仅作为XX项目投标文件组成部分,不得单独使用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "物业装修备案", text: "本件仅用于住宅装修手续登记,有效期至2025年11月30日。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "小区停车位登记", text: "本复印件仅用于业主固定停车位信息备案,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "社区志愿者登记", text: "本复印件仅用于社区志愿服务信息录入,不得外泄。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "遗产继承公证", text: "本件仅用于遗产继承公证程序,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "保险理赔", text: "本复印件仅用于XX保险公司意外险理赔申请,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "物业备案", text: "本复印件仅用于XX小区业主信息备案,不得外传。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "政府补贴申请", text: "本复印件仅用于2025年低收入家庭住房补贴申请,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "人才落户申请", text: "本复印件仅用于XX市人才引进落户申请,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "积分入户材料", text: "本件仅用于2025年XX市积分入户审核,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "公租房申请", text: "本复印件仅用于公共租赁住房资格审核,不得用于其他用途。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "低保申请", text: "本复印件仅用于城乡居民最低生活保障申请,有效期至2025年12月。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "出国定居材料", text: "本复印件仅用于移民XX国定居手续,不得另作他用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "护照换发", text: "本件仅用于普通护照换发申请,有效期至2025年11月30日。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "法院立案材料", text: "本复印件仅用于XX民事案件立案,不得用于其他诉讼。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "仲裁申请", text: "本复印件仅用于劳动争议仲裁提交材料,他用无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "公证委托书附件", text: "本件仅作为委托公证的附件使用,不得单独使用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "遗产分割协议备案", text: "本复印件仅用于遗产分割协议备案,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "驾校报名", text: "本复印件仅用于XX驾校C1驾驶证培训报名使用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "电力开户", text: "本复印件仅用于住宅用电户名登记,不得外泄。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "燃气开户", text: "本件仅用于家庭燃气开户手续,仅限XX燃气公司使用。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "宽带安装", text: "本复印件仅用于XX运营商宽带业务办理,复印无效。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "手机实名制登记", text: "本复印件仅用于手机号码实名认证,不得用于其他业务。", color: "#0000FF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
// 银行类
{ name: "银行贷款专用", text: "本复印件仅用于XX银行个人贷款申请,他用无效。", color: "#FFD700", fontFamily: "Microsoft YaHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "信用卡申请", text: "本件仅用于XX银行信用卡审批,他用无效。", color: "#FFD700", fontFamily: "Microsoft YaHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "贷款结清证明使用", text: "本复印件仅用于贷款结清后征信更新材料,不得挪用。", color: "#FFD700", fontFamily: "Microsoft YaHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
// 政务类
{ name: "车辆年检", text: "本复印件仅用于机动车年度检验,复印无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "残疾证办理", text: "本件仅用于残疾人证申领,仅供残联审核使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "老年证办理", text: "本复印件仅用于60周岁以上老年人优待证办理,他用无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "驾驶证换证", text: "本件仅用于驾驶证期满换证手续,他用无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "房屋过户登记", text: "本复印件仅用于房产过户手续,复印无效,仅供XX不动产登记中心使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "车辆上牌", text: "本复印件仅用于机动车注册登记,仅供车管所使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "法律诉讼材料", text: "本复印件作为XX案件证据提交法院使用,不得另作他用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "学术论文查重材料", text: "本复印件仅用于职称评审论文查重,仅供人事部门使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "教师资格认定", text: "本复印件仅用于中小学教师资格认定申请,复印无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "职称评审材料", text: "本件仅用于2025年度高级工程师职称评审,不得另用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "科研项目申报", text: "本复印件仅用于国家自然科学基金项目申报材料。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "专利申请辅助材料", text: "本件仅用于发明人身份证明,仅供知识产权局审核。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "法人身份证明", text: "本复印件仅用于企业法人代表身份核验,仅供市场监管局使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "房屋租赁备案", text: "本复印件仅用于房屋租赁合同备案登记,有效期至2025年12月。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "房东缴税材料", text: "本件仅用于出租房屋个人所得税申报,仅供税务部门使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "港澳通行证签注", text: "本复印件仅用于个人旅游签注办理,仅供出入境管理部门使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "监护人资格证明", text: "本复印件仅用于未成年人监护关系确认,仅供民政部门使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "领养手续材料", text: "本件仅用于收养登记程序,不得用于其他用途。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "军人家属优待证办理", text: "本复印件仅用于现役军人家属优待政策申请,他用无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "退役军人补贴申领", text: "本件仅用于退役军人生活补贴申报,有效期至2025年12月。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "创业补贴申请", text: "本复印件仅用于高校毕业生创业补贴申请,不得挪用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "失业登记", text: "本件仅用于失业人员信息登记,仅供就业服务中心使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "灵活就业参保", text: "本复印件仅用于灵活就业人员社保参保,复印无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "生育津贴申领", text: "本复印件仅用于生育保险待遇申请,有效期至2025年12月31日。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "新生儿上户口", text: "本复印件仅用于新生儿出生登记,仅供派出所使用。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "疫苗接种证明", text: "本件仅用于儿童预防接种信息核验,他用无效。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
{ name: "工伤认定材料", text: "本件仅用于工伤事故认定申请,不得用于保险骗赔。", color: "#CCCCFF", fontFamily: "SimHei", fontSize: 50, opacity: 0.25, horizontalSpacing: 1200, verticalSpacing: 160, angle: 45 },
];
// 获取 DOM 元素
const imageInput = document.getElementById('imageInput');
const watermarkText = document.getElementById('watermarkText');
const downloadBtn = document.getElementById('downloadBtn');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let originalImage = null;
const opacitySlider = document.getElementById('opacity');
const opacityValue = document.getElementById('opacityValue');
const staggeredToggle = document.getElementById('staggeredToggle');// 错位开关
// 显示当前透明度值
opacityValue.textContent = opacitySlider.value;
opacitySlider.addEventListener('input', () => {
opacityValue.textContent = opacitySlider.value;
updatePreview();
});
// === 动态填充预设选项 ===
function populatePresets() {
presets.forEach(preset => {
const option = document.createElement('option');
option.value = JSON.stringify(preset);
option.textContent = preset.name;
presetSelect.appendChild(option);
});
}
// === 应用选中的预设 ===
function applyPreset() {
const selectedOption = presetSelect.options[presetSelect.selectedIndex];
if (!selectedOption.value) return;
const preset = JSON.parse(selectedOption.value);
watermarkText.value = preset.text;
document.getElementById('color').value = preset.color;
document.getElementById('fontSize').value = preset.fontSize;
document.getElementById('fontFamily').value = preset.fontFamily;
document.getElementById('opacity').value = preset.opacity;
document.getElementById('horizontalSpacing').value = preset.horizontalSpacing;
document.getElementById('verticalSpacing').value = preset.verticalSpacing;
document.getElementById('angle').value = preset.angle;
updatePreview();
}
// === 更新预览 ===
function updatePreview() {
if (!originalImage) return;
// 获取所有参数
const text = watermarkText.value.trim() || '水印';
const angle = parseInt(document.getElementById('angle').value);
const color = document.getElementById('color').value;
const fontSize = document.getElementById('fontSize').value + 'px';
const fontFamily = document.getElementById('fontFamily').value;
const opacity = parseFloat(document.getElementById('opacity').value);
const horizontalSpacing = parseInt(document.getElementById('horizontalSpacing').value);
const verticalSpacing = parseInt(document.getElementById('verticalSpacing').value);
const isStaggered = staggeredToggle.checked; // 是否开启错位
// 设置画布尺寸为原图大小
canvas.width = originalImage.naturalWidth;
canvas.height = originalImage.naturalHeight;
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制原始图片
ctx.drawImage(originalImage, 0, 0);
// 开始绘制水印
ctx.save();
ctx.font = `bold ${fontSize} ${fontFamily}`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// 解析颜色并设置透明度
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${opacity})`;
// 计算中心点用于旋转
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// 应用旋转
ctx.translate(centerX, centerY);
ctx.rotate(angle * Math.PI / 180);
// 网格状绘制水印
const stepX = horizontalSpacing;
const stepY = verticalSpacing;
// 平铺水印
//for (let y = -canvas.height; y < canvas.height * 2; y += stepY) {
// for (let x = -canvas.width; x < canvas.width * 2; x += stepX) {
// ctx.fillText(text, x, y);
// }
//}
// 错位水印
let row = 0;
for (let y = -canvas.height; y < canvas.height * 2; y += stepY) {
const offsetX = isStaggered && row % 2 === 1 ? stepX / 2 : 0; // 奇数行偏移一半
for (let x = -canvas.width; x < canvas.width * 2; x += stepX) {
ctx.fillText(text, x + offsetX, y);
}
row++;
}
ctx.restore(); // 恢复变换
// 启用下载按钮
downloadBtn.disabled = false;
}
// === 图片上传:图片选择事件 ===
imageInput.addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
originalImage = new Image();
originalImage.onload = function () {
updatePreview(); // 图片加载完成后再绘制
};
originalImage.src = event.target.result;
};
reader.readAsDataURL(file);
});
//
// === 所有输入绑定更新:监听所有参数输入事件 ===
[
watermarkText,
document.getElementById('staggeredToggle'),
document.getElementById('angle'),
document.getElementById('color'),
document.getElementById('fontSize'),
document.getElementById('fontFamily'),
document.getElementById('opacity'),
document.getElementById('horizontalSpacing'),
document.getElementById('verticalSpacing')
].forEach(input => {
input.addEventListener('input', updatePreview);
});
// === 下载功能:下载按钮点击事件 ===
downloadBtn.addEventListener('click', function () {
//const link = document.createElement('a');
//link.href = canvas.toDataURL('image/png');
//link.download = 'watermarked_image.png';
//link.click();
// 使用 JPEG 格式,质量设为 0.8(80% 质量,文件更小)
const dataURL = canvas.toDataURL('image/jpeg', 0.8);
const link = document.createElement('a');
link.href = dataURL;
link.download = `watermarked_image_${Date.now()}.jpg`;
link.click();
});
// 页面加载时初始化
window.onload = () => {
populatePresets();
};
</script>
</body>
</html>