(分享)一个图片添加水印的小demo的页面,可自定义样式

news2024/11/15 13:46:36

有时候想给某张图片添加一个自己的水印,但是又懒的下载相应软件,用js canvas制作一个静态页面,对于单张图片添加自定义文字水印,大小 间距,角度可调。
页面如下:
在这里插入图片描述
选择图片,设置相应参数,点击添加水印:
在这里插入图片描述
效果:
在这里插入图片描述
完整程序如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>添加水印</title>
    <link rel="shortcut icon" href="https://img1.imgtp.com/2024/01/09/BKw2wjPL.png" type="image/x-icon">
    <style>
        body {
            background-color: #c8adc4;
        }

        .ml-5 {
            margin-left: 15px;
        }

        .container {
            display: flex;
            justify-content: space-between;
            /* 使两个 div 平均分布在容器中 */
        }

        .box {
            width: 49.5%;
            /* 或根据需要设置 */
            /* 其他样式 */
        }

        #canvas {
            border: 2px solid rgb(210, 208, 208);
            width: 95%;
            height: auto;
            overflow: hidden;
        }

        #p {
            margin-top: 20px;
            width: 95%;
            height: auto;
        }

        #canvas img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        #imageUpload {
            height: auto;
            width: auto;
            font-size: 16px;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="box">
            <div style="border: 2px solid #c9c9c9cc; padding: 10px;">
                <div>
                    <input type="file" id="imageUpload" style="color: rgb(249, 137, 109); margin-left: 40%;">
                </div>
                <div style="margin-left: 10%;margin-top: 30px;">
                    <span>大小:</span><input type="text" placeholder="修改水印大小" style="height: 24px;width: 100px;"
                        value="100" id="ipt1">
                    <span class="ml-5">透明度:</span><input type="text" placeholder="范围1~10"
                        style="height: 24px;width: 100px;" value="5" id="ipt2">
                    <span class="ml-5">间距:</span><input type="text" placeholder="范围1-10"
                        style="height: 24px;width: 100px;" value="5" id="ipt3">
                </div>
                <div style="margin-top: 20px;margin-left: 10%;">
                    <span class="ml-5">倾斜方向:</span>
                    <select id="s2">
                        <option value="left">左倾斜</option>
                        <option value="right">右倾斜</option>
                    </select>
                    <span class="ml-5">倾斜角度:</span>
                    <input type="text" placeholder="修改倾斜大小" style="height: 20px;width: 30px;" value="30" id="ipt4"><span
                        style="margin-left: 5px; ;"></span>
                </div>
                <div style="margin-left: 10%;margin-top: 40px;">
                    文本:<input type="text" id="watermarkText" placeholder="请输入水印内容" style="height: 24px;">
                    <button id="confirmButton"
                        style="margin-left: 100px; width: 80px;height: 30px;background-color: rgb(127, 214, 255);color: white;font-size: 16px;border: none;border-radius: 5px;">添加水印</button>
                    <button id="saveButton"
                        style="width: 60px;height: 30px;background-color: rgb(28, 119, 161);color: white;font-size: 16px;border: none;border-radius: 5px;">下载</button>
                    <button id="reflash" onclick="flush()"
                        style="width: 80px;height: 30px;background-color: rgb(248, 126, 81);color: white;font-size: 16px;border: none;border-radius: 5px;">重置页面</button>
                </div>
            </div>
            <span style="color: rgb(255, 255, 255); font-weight: bold;font-size: 20px;">原图:</span>
            <img id="p"></img>
        </div>
        <div class="box">
            <span style="color: rgb(255, 255, 255); font-weight: bold;font-size: 20px;">预览框:</span>
            <canvas id="canvas"></canvas>
        </div>
    </div>
    <script>

        //回显
        document.getElementById('imageUpload').addEventListener('change', function (e) {
            var reader = new FileReader();
            reader.onload = function (e) {
                document.getElementById('p').src = e.target.result;
                document.getElementById('p').style.display = 'block';
            }
            reader.readAsDataURL(e.target.files[0]);
        })

        //添加水印
        document.getElementById('confirmButton').addEventListener('click', function () {
            var image = document.getElementById('imageUpload').files[0]; //图片对象
            var watermarkText = document.getElementById('watermarkText').value; //水印对象
            var canvas = document.getElementById('canvas');  //canvas
            var ctx = canvas.getContext('2d');
            var img = new Image(); //img对象
            var fontsize = document.getElementById('ipt1').value; //初始大小
            var transparency = document.getElementById('ipt2').value / 10; //透明度
            var jianju = document.getElementById('ipt3').value; //间距
            //单行多行
            
            //倾斜方式
            var tilt = document.getElementById('s2').value;
            var angle = document.getElementById('ipt4').value;
            img.onload = function () {
                canvas.width = img.width;
                canvas.height = img.height;
                ctx.drawImage(img, 0, 0, img.width, img.height);
                ctx.font = fontsize + 'px Arial'; //大小 字体
                ctx.fillStyle = `rgba(170, 171, 172, ${transparency})`;
                if (tilt === 'left') painWatermarket_left(watermarkText, canvas, jianju, ctx, angle);
                if (tilt === 'right') painWatermarket_right(watermarkText, canvas, jianju, ctx, angle);
            };
            img.src = URL.createObjectURL(image);
        });

        // 单行左倾斜params: watermarkText canvas jianju\ 
        function painWatermarket_left(watermarkText, canvas, jianju, ctx, angle, lineNumber) {
            var txtLen = Math.ceil(ctx.measureText(watermarkText).width / 2);
            for (var i = 150 - txtLen, j = 150 - txtLen;
                i < canvas.width, j < canvas.height;
                i += canvas.width / jianju, j += canvas.height / jianju) {
                ctx.save();
                ctx.translate(i, j);
                ctx.rotate(angle * Math.PI / 180);
                ctx.fillText(watermarkText, 0, 0);
                ctx.restore();
            }

        }

        // 单行右倾斜params: watermarkText canvas jianju
        function painWatermarket_right(watermarkText, canvas, jianju, ctx, angle) {
            angle = -1 * angle;
            var txtLen = Math.ceil(ctx.measureText(watermarkText).width / 2); //文本宽度
            for (var i = 150 - txtLen, j = canvas.height; i < canvas.width, j > 150 - txtLen; i += canvas.width / jianju, j -= canvas.height / jianju) {
                ctx.save();
                ctx.translate(i, j);
                ctx.rotate(angle * Math.PI / 180);
                ctx.fillText(watermarkText, 0, 0);
                ctx.restore();
            }
        }

        //保存
        document.getElementById('saveButton').addEventListener('click', function () {
            var canvas = document.getElementById('canvas');
            var dataUrl = canvas.toDataURL('image/png');
            var blob = dataURItoBlob(dataUrl);
            var link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = 'demo.png';
            link.click();
        });

        function dataURItoBlob(dataURI) {
            var byteString;
            if (dataURI.split(',')[0].indexOf('base64') >= 0)
                byteString = atob(dataURI.split(',')[1]);
            else
                byteString = unescape(dataURI.split(',')[1]);

            var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
            }
            return new Blob([ab], { type: mimeString });
        }
        //重置
        function flush() {
            location.reload();
        }
    </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1546747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习模型部署(十二)CUDA编程-绪

CUDA 运行时 API 与 CUDA 驱动 API 速度没有差别&#xff0c;实际中使用运行时 API 较多&#xff0c;运行时 API 是在驱动 API 上的一层封装。​ CUDA 是什么&#xff1f;​ CUDA(Compute Unified Device Architecture) 是 nvidia 推出的一个通用并行技术架构&#xff0c;用它…

【LLM】大模型推理加速 KV-Cache

目录 模型推理过程KV Cache原理KV Cache的存储 模型推理过程 在了解KVCache之前&#xff0c;我们需要知道Transformer类大模型的推理过程。 对于LLM进行一次前向传播也就是生成一个token的过程可以被分解成以下步骤&#xff1a; 文本 T i n p u t T_{input} Tinput​经过Toke…

数据结构与算法分析引论1

1.解决问题的算法有很多&#xff0c;但是在输入不同的情况下&#xff0c;不同算法之间的差异也很大&#xff0c;我们总是追求一个更快、更有效的方法。比如说普通的依次查找和二分查找&#xff0c;两者的差异就很大。我们使用大O表示法来表示算法的速度。依次查找就是O(n)&…

MATLAB 自定义生成平面点云(可指定方向,添加噪声)(48)

MATLAB 自定义生成平面点云(可指定方向,添加噪声)(48) 一、算法介绍二、算法步骤三、算法实现1.代码2.效果一、算法介绍 通过这里的平面生成方法,可以生成模拟平面的点云数据,并可以人为设置平面方向,平面大小,并添加噪声来探索不同类型的平面数据。这种方法可以用于…

UDS诊断中的NRC

我总结了一张表格&#xff1a;详细解释了NRC的分布情况和NRC的触发条件 1&#xff1a;基本概念 NRC 全称Negative Response Code(否定响应代码)&#xff0c;是指示uds诊断中的&#xff0c;指示否定响应的原因 例如&#xff1a;0x22 服务 request 报文 0x618 03 22 F1 34 0…

电脑物理磁盘空间不足?试试这5种清理和优化方法!

随着我们使用电脑的时间越来越长&#xff0c;物理磁盘空间可能会逐渐变得捉襟见肘。当你的电脑提示磁盘空间不足时&#xff0c;不要慌张&#xff0c;这里有五种方法可以帮助你清理和优化电脑&#xff0c;释放宝贵的存储空间。 1. 卸载不常用的程序和游戏 许多用户在安装软件和…

机器学习基础——模型评估与选择(部分)

目录 一、前言&#xff1a;误差与拟合 &#xff08;一&#xff09;经验误差 &#xff08;二&#xff09;过拟合、欠拟合 二、评估方法 &#xff08;一&#xff09;评估总体的思路 &#xff08;二&#xff09;如何划分训练集和测试集 1.留出法 2.k折交叉验证 3.自助法 …

程序员35岁真的就是危机吗?

前言 35岁被认为是程序员职业生涯的分水岭&#xff0c;许多程序员开始担忧自己的职业发展是否会受到年龄的限制。有人担心随着年龄的增长&#xff0c;技术更新换代的速度会使得资深程序员难以跟上&#xff1b;而另一些人则认为&#xff0c;丰富的经验和深厚的技术积累是年轻程…

knife4j/swagger救援第一现场

1、前方来报&#xff0c;测试环境springboot项目无法启动&#xff0c;现场如下&#xff1a; Error starting ApplicationContext. To display the auto-configuration report re-run your application with debug enabled. [ERROR] 2024-03-20 12:54:42,718 --main-- [org.spr…

一键跳过开屏广告,这下舒服了

现在的app开屏广告越来越过分了&#xff0c;不小心摇一摇翻转就点开广告了。 今天分享个强大的自动跳过广告https://github.com/gkd-kit/gkd&#xff0c;李跳跳替代品&#xff0c;下载地址在公众号后台对话框回复 广告 玩转互联网达人 苏生不惑备用号&#xff0c;分享各种黑科…

【Godot4自学手册】第二十九节使用Shader来实现敌人受伤的闪白效果

在Godot 4中&#xff0c;Shader是用来为材质提供自定义渲染效果的程序。材质可以应用于MeshInstance、CanvasItem和ParticleEmitter等节点。Shader可以影响顶点的变换、片段&#xff08;像素&#xff09;的颜色&#xff0c;以及光照与物体的交互。 在Godot中&#xff0c;Shader…

HTML基础:8个常见表单元素的详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端程序媛。 后台回复“前端工具”可免费获取开发工具&#xff0c;持续更新。 今天来说说 HTML 表单。它是用于收集用户输入信息的元素集合。例如文本框、单选按钮、复选框、下拉列表等。 用户经常填写的表…

海外媒体软文发稿:谷歌关键词优化细分人群成功案例,突破海外市场!

海外媒体软文发稿&#xff1a;谷歌关键词优化细分人群成功案例&#xff0c;突破海外市场&#xff01; 引言 在全球化的时代&#xff0c;海外市场对于企业的发展至关重要。而在海外市场中&#xff0c;互联网媒体的作用不可忽视。本篇教程将介绍如何通过谷歌关键词优化细分人群…

西井科技与安通控股签署战略合作协议 共创大物流全新生态

2024年3月21日&#xff0c;西井科技与安通控股在“上海硅巷”新象限空间正式签署战略合作框架协议。双方基于此前在集装箱物流的成功实践与资源优势&#xff0c;积极拓展在AI数字化产品、新能源自动驾驶解决方案和多场景应用&#xff0c;以及绿色物流链等领域的深度探索、强强联…

2024.3.23

1、使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否…

鸿蒙应用开发-录音并使用WebSocket实现实时语音识别

功能介绍&#xff1a; 录音并实时获取RAW的音频格式数据&#xff0c;利用WebSocket上传数据到服务器&#xff0c;并实时获取语音识别结果&#xff0c;参考文档使用AudioCapturer开发音频录制功能(ArkTS)&#xff0c;更详细接口信息请查看接口文档&#xff1a;AudioCapturer8和…

如何推进制造业数字化转型?《制造业数字化转型白皮书》分享给你

分享一份《制造业数字化转型白皮书》给你&#xff0c;希望对你有所帮助&#xff01; 内容较长&#xff0c;防止后续找不到&#xff0c;建议先收藏&#xff01; 变局&#xff1a;数字经济浪潮“不期而至” 中国制造何去何从&#xff1f; VUCA&#xff08;不稳定 Volatile、不确…

超详细SpringMVC源码剖析

整体流程图 1.自定义视图(63~66) 视图解析过程 1.先到DispatcherServlet中央控制器, 根据视图解析的 优先级 执行对应的 视图解析器 Nullable protected View resolveViewName(String viewName, Nullable Map<String, Object> model,Locale locale, HttpServletReque…

美团面试一面凉经

1.自我介绍 2.科研项目提问 没咋准备&#xff0c;说的有点没逻辑 3.问论坛项目 为什么用Redis实现登录&#xff1f;能不能用其他方式实现&#xff1f; 1、Redis 具备高性能 假如用户第一次访问 MySQL 中的某些数据。这个过程会比较慢&#xff0c;因为是从硬盘上读取的。将…

Springboot+vue的企业质量管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的企业质量管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…