前端JavaScript实现图片水印生成的具体指南_javascript技巧
今天,我将手把手教你用前端技术给图片"纹身",就像给贵重物品刻上姓名一样简单。无需后端,打开浏览器就能完成!
// 就像准备画板和颜料const canvas = document.createElement("canvas");const ctx = canvas.getContext("2d");// 把照片铺在画板上ctx.drawImage(img, 0, 0);// 用半透明"墨水"写字ctx.fillStyle = "rgba(0,0,0,0.3)";ctx.fillText("机密", 100, 100);// 把画好的作品拍成照片canvas.toDataURL("image/jpeg");
新手推荐 :Canvas方案就像多功能纹身机,能满足大部分需求!
第一步:使用 fileReader 读取文件
const reader = new FileReader();reader.onload = (e) => { const img = new Image(); img.onload = () => { resolve(img); }; img.onerror = (err) => { reject(err); }; img.src = e.target.result; // 将 Base64 数据赋值给 Image 的 src 属性};reader.onerror = (err) => { reject(err);};reader.readAsDataURL(file); // 以 Data URL 的形式读取文件
FileReader.readAsDataURL(file):
const img = new Image();img.onload = () => { resolve(img);};img.onerror = (err) => { reject(err);};img.src = e.target.result; // 将 Base64 数据赋值给 Image 的 src 属性
img.src = e.target.result:
这两步操作是紧密相连的异步流程,具体联系如下:
这种设计使得异步操作可以被很好地管理,代码逻辑清晰且易于维护。
// 当顾客上传照片时uploader.addEventListener("change", async (e) => { const file = e.target.files[0]; if(!file) return; // 开始纹身! const protectedImage = await tattooImage(file); // 展示成品 photoFrame.innerHTML = ``;});
动态水印:添加当前日期
ctx.fillText(`张三 ${new Date().toLocaleDateString()}`, x, y);
图片水印:用Logo代替文字
const logo = await loadImage("logo.png");ctx.drawImage(logo, x, y, 50, 50);
多重防护:文字+图案组合水印
针对已经存在于本地服务器或网络上的图片,我将提供两种场景的完整解决方案,并解释其中的关键差异。
必须设置跨域属性:
img.crossOrigin = "Anonymous"; // 必须!
开发环境CORS配置(以Express为例):
// 在Node.js服务器添加这段代码app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); next();});
缓存问题处理:
img.src = url + '?t=' + Date.now(); // 加时间戳避免缓存
async function addWatermarkToWebImage(imageUrl) { try { // 方案1:直接尝试(需要图片服务器允许跨域) const result = await tryDirectWatermark(imageUrl); if (result) return result; // 方案2:通过后端代理(当直接访问失败时) return await fetchProxyWatermark(imageUrl); } catch (error) { console.error("水印生成失败:", error); return null; }}// 尝试直接加水印async function tryDirectWatermark(url) { return new Promise((resolve) => { const img = new Image(); img.crossOrigin = "Anonymous"; img.src = url; img.onload = function() { // ...(与本地服务器相同的加水印逻辑) resolve(watermarkedImage); }; img.onerror = () => resolve(null); // 失败返回null });}// 通过后端代理获取async function fetchProxyWatermark(url) { const response = await fetch(`/api/watermark-proxy?url=${encodeURIComponent(url)}`); const blob = await response.blob(); return URL.createObjectURL(blob);}
关键注意事项
跨域问题处理流程:
// 代理接口实现app.get('/api/watermark-proxy', async (req, res) => { const { url } = req.query; try { const response = await axios.get(url, { responseType: 'arraybuffer' }); res.type(response.headers['content-type']); res.send(response.data); } catch (error) { res.status(500).send("图片获取失败"); }});