Greasy Fork is available in English.

js-watermark

JavaScript 图片文字水印、图片图片水印生成工具,生成 base64 编码图片。

Ezt a szkriptet nem ajánlott közvetlenül telepíteni. Ez egy könyvtár más szkriptek számára, amik tartalmazzák a // @require https://update.greasyfork.org/scripts/452322/1470429/js-watermark.js hivatkozást.

  1. // @ts-nocheck
  2. /**
  3. * @js-watermark.js
  4. * @author WhiteSev
  5. * @Created: 22-09-26
  6. * @repository: https://github.com/WhiteSevs/js-watermark
  7. * @forked by:https://github.com/gisonyeung/js-watermark
  8. * @description JavaScript 图片文字水印、图片图片水印生成工具,生成 base64 编码图片。
  9. */
  10.  
  11. (function (global, factory) {
  12. /**
  13. * 不使用define
  14. * typeof define === "function" && define.amd
  15. * define(factory)
  16. */
  17. if (typeof exports === "object" && typeof module !== "undefined") {
  18. /* 适用于NodeJs或typeScript */
  19. module.exports = factory();
  20. } else {
  21. global = typeof globalThis !== "undefined" ? globalThis : global || self;
  22. /* 适用于浏览器中,且this对象是window,如果this是其它,那么会在其它对象下注册对象 */
  23. global.Watermark = factory(global.Watermark);
  24. }
  25. })(typeof window !== "undefined" ? window : this, function (AnotherWatermark) {
  26. "use strict";
  27. /**
  28. * @class
  29. */
  30. let Watermark = function () {};
  31. /**
  32. * @author zhangxinxu(.com)
  33. * @licence MIT
  34. * @description http://www.zhangxinxu.com/wordpress/?p=7362
  35. */
  36. /* api扩展-设置字符间距 */
  37. CanvasRenderingContext2D.prototype.letterSpacingText = function (
  38. text,
  39. x,
  40. y,
  41. letterSpacing
  42. ) {
  43. var context = this;
  44. var canvas = context.canvas;
  45.  
  46. if (!letterSpacing && canvas) {
  47. letterSpacing = parseFloat(window.getComputedStyle(canvas).letterSpacing);
  48. }
  49. if (!letterSpacing) {
  50. return this.fillText(text, x, y);
  51. }
  52.  
  53. var arrText = text.split("");
  54. var align = context.textAlign || "left";
  55.  
  56. /* 这里仅考虑水平排列 */
  57. var originWidth = context.measureText(text).width;
  58. /* 应用letterSpacing占据宽度 */
  59. var actualWidth = originWidth + letterSpacing * (arrText.length - 1);
  60. /* 根据水平对齐方式确定第一个字符的坐标 */
  61. if (align == "center") {
  62. x = x - actualWidth / 2;
  63. } else if (align == "right") {
  64. x = x - actualWidth;
  65. }
  66.  
  67. /* 临时修改为文本左对齐 */
  68. context.textAlign = "left";
  69. /* 开始逐字绘制 */
  70. arrText.forEach(function (letter) {
  71. var letterWidth = context.measureText(letter).width;
  72. context.fillText(letter, x, y);
  73. /* 确定下一个字符的横坐标 */
  74. x = x + letterWidth + letterSpacing;
  75. });
  76. /* 对齐方式还原 */
  77. context.textAlign = align;
  78. };
  79.  
  80. /* api扩展-自动换行 */
  81. CanvasRenderingContext2D.prototype.wrapText = function (
  82. text,
  83. x,
  84. y,
  85. maxWidth,
  86. lineHeight,
  87. stroke
  88. ) {
  89. if (
  90. typeof text != "string" ||
  91. typeof x != "number" ||
  92. typeof y != "number"
  93. ) {
  94. return;
  95. }
  96.  
  97. var context = this;
  98. var canvas = context.canvas;
  99.  
  100. if (typeof maxWidth == "undefined") {
  101. maxWidth = (canvas && canvas.width) || 300;
  102. }
  103. if (typeof lineHeight == "undefined") {
  104. lineHeight =
  105. (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) ||
  106. parseInt(window.getComputedStyle(document.body).lineHeight);
  107. }
  108.  
  109. /* 字符分隔为数组 */
  110. var arrText = text.split("");
  111. var line = "";
  112.  
  113. for (var n = 0; n < arrText.length; n++) {
  114. var testLine = line + arrText[n];
  115. var metrics = context.measureText(testLine);
  116. var testWidth = metrics.width;
  117. if (testWidth > maxWidth && n > 0) {
  118. if (stroke) {
  119. context.strokeText(line, x, y, canvas.width);
  120. } else {
  121. context.fillText(line, x, y);
  122. }
  123. line = arrText[n];
  124. y += lineHeight;
  125. } else {
  126. line = testLine;
  127. }
  128. }
  129. if (stroke) {
  130. context.strokeText(line, x, y, canvas.width);
  131. } else {
  132. context.fillText(line, x, y);
  133. }
  134. };
  135.  
  136. /* api扩展-垂直排列 */
  137. CanvasRenderingContext2D.prototype.fillTextVertical = function (text, x, y) {
  138. var context = this;
  139. var canvas = context.canvas;
  140.  
  141. var arrText = text.split("");
  142. var arrWidth = arrText.map(function (letter) {
  143. return context.measureText(letter).width;
  144. });
  145.  
  146. var align = context.textAlign;
  147. var baseline = context.textBaseline;
  148.  
  149. if (align == "left") {
  150. x = x + Math.max.apply(null, arrWidth) / 2;
  151. } else if (align == "right") {
  152. x = x - Math.max.apply(null, arrWidth) / 2;
  153. }
  154. if (
  155. baseline == "bottom" ||
  156. baseline == "alphabetic" ||
  157. baseline == "ideographic"
  158. ) {
  159. y = y - arrWidth[0] / 2;
  160. } else if (baseline == "top" || baseline == "hanging") {
  161. y = y + arrWidth[0] / 2;
  162. }
  163.  
  164. context.textAlign = "center";
  165. context.textBaseline = "middle";
  166.  
  167. /* 开始逐字绘制 */
  168. arrText.forEach(function (letter, index) {
  169. /* 确定下一个字符的纵坐标位置 */
  170. var letterWidth = arrWidth[index];
  171. /* 是否需要旋转判断 */
  172. var code = letter.charCodeAt(0);
  173. if (code <= 256) {
  174. context.translate(x, y);
  175. /* 英文字符,旋转90° */
  176. context.rotate((90 * Math.PI) / 180);
  177. context.translate(-x, -y);
  178. } else if (index > 0 && text.charCodeAt(index - 1) < 256) {
  179. /* y修正 */
  180. y = y + arrWidth[index - 1] / 2;
  181. }
  182. context.fillText(letter, x, y);
  183. /* 旋转坐标系还原成初始态 */
  184. context.setTransform(1, 0, 0, 1, 0, 0);
  185. /* 确定下一个字符的纵坐标位置 */
  186. var letterWidth = arrWidth[index];
  187. y = y + letterWidth;
  188. });
  189. /* 水平垂直对齐方式还原 */
  190. context.textAlign = align;
  191. context.textBaseline = baseline;
  192. };
  193.  
  194. /**
  195. * 加载File对象
  196. *
  197. * @param {File} file
  198. * @async
  199. * @returns {Promise<ProgressEvent<FileReader>>}
  200. */
  201. function loadFile(file) {
  202. let fileReader = new FileReader();
  203. return new Promise((resolve) => {
  204. fileReader.onloadend = async function (event) {
  205. resolve(event);
  206. };
  207. fileReader.readAsDataURL(file);
  208. });
  209. }
  210.  
  211. /**
  212. * 加载Image对象
  213. *
  214. * @param {string} src
  215. * @async
  216. * @returns {Promise<HTMLImageElement>}
  217. */
  218. function loadImage(src) {
  219. let image = new Image();
  220.  
  221. return new Promise((resolve) => {
  222. image.onload = () => {
  223. resolve(image);
  224. };
  225. image.src = src;
  226. });
  227. }
  228. /**
  229. * 检查坐标是否重复
  230. * @param {any[]} arrayData
  231. * @param {number} x
  232. * @param {number} y
  233. * @returns {boolean}
  234. */
  235. function checkInArrayByPos(arrayData, x, y) {
  236. let flag = false;
  237. Array.from(arrayData).forEach((item) => {
  238. if (item["x"] == x && item["y"] == y) {
  239. flag = true;
  240. return;
  241. }
  242. });
  243. return flag;
  244. }
  245. /**
  246. * 获取文字占据的宽度,高度
  247. * @param {string} char
  248. * @param {any} style
  249. * @returns {{height:Number,width:Number}}
  250. */
  251. function getCharSizeByCanvas(char, style = {}) {
  252. let textCanvas = document.createElement("canvas");
  253. textCanvas.style.positon = "ablsolute";
  254. let textCTX = textCanvas.getContext("2d");
  255. let { fontSize = 14, fontFamily = "Microsoft Yahei" } = style;
  256. document.body.appendChild(textCanvas);
  257. textCTX.font = `${fontSize}px ${fontFamily}`;
  258. document.body.removeChild(textCanvas);
  259. let text = textCTX.measureText(char); /* TextMetrics object */
  260. textCTX.fillText(char, 50, 50);
  261. let result = {
  262. height: parseInt(fontSize),
  263. width: parseInt(text.width),
  264. };
  265. return result;
  266. }
  267. /**
  268. * 获取随机值
  269. * @param {any[]} arr
  270. */
  271. function getRandValue(arr) {
  272. if (arr instanceof Array) {
  273. return arr[Math.floor(Math.random() * arr.length)];
  274. } else {
  275. return arr;
  276. }
  277. }
  278. /**
  279. * 通过 file 对象载入图片文件-异步
  280. * @async
  281. * @param {File} file
  282. * @returns {Promise<boolean>}
  283. */
  284. Watermark.prototype.setFile = function (file) {
  285. let that = this;
  286. return new Promise(async (resolve) => {
  287. try {
  288. var fileReader = await loadFile(file);
  289. await that.setImage(fileReader.target.result);
  290. resolve(true);
  291. } catch (error) {
  292. resolve(false);
  293. }
  294. });
  295. };
  296. /**
  297. * 通过 base64 载入图片文件-异步
  298. * @param {string} src
  299. * @async
  300. * @returns {Promise<boolean>}
  301. */
  302. Watermark.prototype.setImage = function (src) {
  303. this.dataUrl = src;
  304. let that = this;
  305. return new Promise(async (res) => {
  306. var image = await loadImage(src);
  307. that.sizes = {
  308. width: image.width,
  309. height: image.height,
  310. };
  311.  
  312. var canvas = document.createElement("canvas");
  313.  
  314. canvas.width = that.sizes.width;
  315. canvas.height = that.sizes.height;
  316. var ctx = canvas.getContext("2d");
  317.  
  318. ctx.drawImage(image, 0, 0);
  319. image = null;
  320. that.canvas = canvas;
  321. res(true);
  322. });
  323. };
  324.  
  325. /**
  326. * 获取是否存在图片对象
  327. * @returns {boolean}
  328. */
  329. Watermark.prototype.hasImage = function () {
  330. return !!this.dataUrl;
  331. };
  332.  
  333. /**
  334. * 获取当前图片尺寸
  335. * @returns {number}
  336. */
  337. Watermark.prototype.getSize = function () {
  338. return this.sizes;
  339. };
  340.  
  341. /**
  342. * 清空水印
  343. */
  344. Watermark.prototype.clearMark = function () {
  345. let that = this;
  346. if (typeof that.canvas === "undefined") {
  347. return;
  348. }
  349.  
  350. function _clearMark_() {
  351. var ctx = that.canvas.getContext("2d");
  352. /* 清空画布 */
  353. ctx.clearRect(0, 0, that.canvas.width, that.canvas.height);
  354. var w = that.canvas.width;
  355. var h = that.canvas.height;
  356. that.canvas.width = w;
  357. that.canvas.height = h;
  358. /* 清除path路径 */
  359. ctx.beginPath();
  360. /* 重绘 */
  361. var image = new Image();
  362. image.src = that.dataUrl;
  363. ctx.drawImage(image, 0, 0);
  364. image = null;
  365. }
  366. _clearMark_();
  367. };
  368.  
  369. /**
  370. * 添加文字水印(全屏)
  371. * @param {object} opts
  372. */
  373. Watermark.prototype.addText = function (opts) {
  374. var options = {
  375. text: ["Call By waterMark.addText"],
  376. fontSize: "6vw",
  377. fontFamily: "Microsoft Yahei",
  378. color: "#000000",
  379. textAlign: "center",
  380. /* 描边 */
  381. stroke: false,
  382. globalAlpha: 0.7,
  383. /* -360 ~ 360 */
  384. rotateAngle: 50,
  385. /* 必须大于0 */
  386. maxWidth: 100,
  387. /* 必须大于0 */
  388. xMoveDistance: 30,
  389. /* 必须大于0 */
  390. yMoveDistance: 30,
  391. };
  392. for (let key in options) {
  393. if (typeof opts[key] !== "undefined") {
  394. options[key] = opts[key];
  395. }
  396. }
  397. options.maxWidth = parseInt(options.maxWidth) > 0 ? options.maxWidth : 1;
  398. options.xMoveDistance =
  399. parseInt(options.xMoveDistance) > 0 ? options.xMoveDistance : 1;
  400. options.yMoveDistance =
  401. parseInt(options.yMoveDistance) > 0 ? options.yMoveDistance : 1;
  402. var ctx = this.canvas.getContext("2d");
  403.  
  404. var fontSize = options.fontSize;
  405. fontSize = fontSize.toString();
  406. /* 转换 vw */
  407. if (~fontSize.indexOf("vw")) {
  408. fontSize = ((this.sizes.width / 100) * parseInt(fontSize)).toFixed(0);
  409. }
  410. fontSize = parseInt(fontSize);
  411.  
  412. /* 绘制水印 */
  413. ctx.font = fontSize + "px " + options.fontFamily;
  414. ctx.fillStyle = options.color;
  415. ctx.textAlign = options.textAlign;
  416. ctx.globalAlpha = options.globalAlpha; /* 透明度 */
  417.  
  418. let canvasWidth = this.sizes.width,
  419. /* 画布宽高 */
  420. canvasHeight = this.sizes.height;
  421. let rotateAngle = (options.rotateAngle * Math.PI) / 180;
  422. let xMoveDistance = options.xMoveDistance; /* 水平移动距离 */
  423. let yMoveDistance = options.yMoveDistance; /* 垂直移动距离 */
  424. let maxWidth = options.maxWidth; /* 文字最大宽度 */
  425. let lineHeight = fontSize; /* 文字占据高度 */
  426. let pos = [];
  427. for (var i = canvasWidth / 2; i < canvasWidth; i += xMoveDistance) {
  428. /* 右侧铺满 */
  429. for (var j = canvasHeight / 2; j < canvasHeight; j += yMoveDistance) {
  430. /* 右下 */
  431. if (!checkInArrayByPos(pos, i, j)) {
  432. pos = pos.concat({
  433. x: i,
  434. y: j,
  435. });
  436. ctx.setTransform(1, 0, 0, 1, 0, 0);
  437. ctx.translate(i, j);
  438. ctx.rotate(rotateAngle);
  439. ctx.wrapText(
  440. getRandValue(options.text),
  441. 0,
  442. 0,
  443. maxWidth,
  444. lineHeight,
  445. options.stroke
  446. );
  447. }
  448. }
  449. for (var k = canvasHeight / 2; k > 0; k -= yMoveDistance) {
  450. /* 右上 */
  451. if (!checkInArrayByPos(pos, i, k)) {
  452. pos = pos.concat({
  453. x: i,
  454. y: k,
  455. });
  456. ctx.setTransform(1, 0, 0, 1, 0, 0);
  457. ctx.translate(i, k);
  458. ctx.rotate(rotateAngle);
  459. ctx.wrapText(
  460. getRandValue(options.text),
  461. 0,
  462. 0,
  463. maxWidth,
  464. lineHeight,
  465. options.stroke
  466. );
  467. }
  468. }
  469. }
  470.  
  471. for (var i = canvasWidth / 2; i > 0; i -= xMoveDistance) {
  472. /* 左侧铺满 */
  473. for (var j = canvasHeight / 2; j < canvasHeight; j += yMoveDistance) {
  474. /* 左下 */
  475. if (!checkInArrayByPos(pos, i, j)) {
  476. pos = pos.concat({
  477. x: i,
  478. y: j,
  479. });
  480. ctx.setTransform(1, 0, 0, 1, 0, 0);
  481. ctx.translate(i, j);
  482. ctx.rotate(rotateAngle);
  483. ctx.wrapText(
  484. getRandValue(options.text),
  485. 0,
  486. 0,
  487. maxWidth,
  488. lineHeight,
  489. options.stroke
  490. );
  491. }
  492. }
  493. for (var k = canvasHeight / 2; k > 0; k -= yMoveDistance) {
  494. /* 左上 */
  495. if (!checkInArrayByPos(pos, i, k)) {
  496. pos = pos.concat({
  497. x: i,
  498. y: k,
  499. });
  500. ctx.setTransform(1, 0, 0, 1, 0, 0);
  501. ctx.translate(i, k);
  502. ctx.rotate(rotateAngle);
  503. ctx.wrapText(
  504. getRandValue(options.text),
  505. 0,
  506. 0,
  507. maxWidth,
  508. lineHeight,
  509. options.stroke
  510. );
  511. }
  512. }
  513. }
  514. };
  515.  
  516. /**
  517. * 添加像素文字水印(单个)
  518. * @param {object} opts
  519. */
  520. Watermark.prototype.addPixelText = function (opts) {
  521. var options = {
  522. text: "像素文字水印",
  523. /* 像素文字 */
  524. big: {
  525. fontSize: 150,
  526. fontFamily: "微软雅黑",
  527. textAlign: "center",
  528. rotateAngle: 0,
  529. /* 描边 */
  530. stroke: false,
  531. },
  532. /* 绘制像素的文字 */
  533. small: {
  534. fontSize: 10,
  535. fontFamily: "微软雅黑",
  536. color: "#000",
  537. textAlign: "center",
  538. globalAlpha: 0.7,
  539. },
  540. };
  541. for (let key in options) {
  542. if (typeof opts[key] !== "undefined") {
  543. options[key] = opts[key];
  544. }
  545. }
  546. var ctx = this.canvas.getContext("2d");
  547. var tmpCanvas = document.createElement("canvas");
  548. var tmpctx = tmpCanvas.getContext("2d");
  549. tmpCanvas.width = this.sizes.width;
  550. tmpCanvas.height = this.sizes.height;
  551. tmpctx.font = options.big.fontSize + "px " + options.big.fontFamily;
  552. tmpctx.textAlign = options.big.textAlign;
  553. tmpctx.textBaseline = "middle";
  554. tmpctx.translate(tmpCanvas.width / 2, tmpCanvas.height / 2);
  555. tmpctx.rotate((options.big.rotateAngle * Math.PI) / 180);
  556. tmpctx.translate(-tmpCanvas.width / 2, -tmpCanvas.height / 2);
  557. if (options.big.stroke) {
  558. tmpctx.strokeText(
  559. options.text,
  560. tmpCanvas.width / 2,
  561. tmpCanvas.height / 2,
  562. tmpCanvas.width
  563. );
  564. } else {
  565. tmpctx.fillText(options.text, tmpCanvas.width / 2, tmpCanvas.height / 2);
  566. }
  567.  
  568. var textArray = options.text.split("");
  569. var textPixleInfo = tmpctx.getImageData(
  570. 0,
  571. 0,
  572. tmpCanvas.width,
  573. tmpCanvas.height
  574. );
  575. var pixelArray = [];
  576. for (var i = 0; i < tmpCanvas.height; i += options.small.fontSize) {
  577. for (var j = 0; j < tmpCanvas.width; j += options.small.fontSize) {
  578. var index = j + i * tmpCanvas.width;
  579. var a = textPixleInfo.data[index * 4 + 3];
  580. if (a > 128) {
  581. //存入数组
  582. pixelArray.push({
  583. text: getRandValue(textArray),
  584. x: j,
  585. y: i,
  586. });
  587. }
  588. }
  589. }
  590.  
  591. ctx.font = options.small.fontSize + "px " + options.small.fontFamily;
  592. ctx.fillStyle = options.small.color;
  593. ctx.textAlign = options.small.textAlign;
  594. ctx.textBaseline = "middle";
  595. ctx.globalAlpha = options.small.globalAlpha;
  596. pixelArray.forEach((item) => {
  597. ctx.fillText(item.text, item.x, item.y);
  598. });
  599. };
  600.  
  601. /**
  602. * 添加图片水印(全屏)
  603. * @param {object} opts
  604. * @returns
  605. */
  606. Watermark.prototype.addImage = function (opts) {
  607. if (opts.imageArray == null) {
  608. alert("参数缺少imageArray");
  609. return false;
  610. }
  611. if (opts.imageArray.length === 0) {
  612. alert("参数imageArray不能为空");
  613. return false;
  614. }
  615. let options = {
  616. imageArray: [],
  617. /* 里面为水印Image对象 */
  618. width: 50,
  619. /* 必须大于0 */
  620. height: 50,
  621. /* 必须大于0 */
  622. globalAlpha: 0.5,
  623. rotateAngle: 0,
  624. xMoveDistance: 70,
  625. /* 必须大于0 */
  626. yMoveDistance: 70,
  627. /* 必须大于0 */
  628. };
  629. for (let key in options) {
  630. if (typeof opts[key] !== "undefined") {
  631. options[key] = opts[key];
  632. }
  633. }
  634. options.width = parseInt(options.width) > 0 ? options.width : 1;
  635. options.height = parseInt(options.height) > 0 ? options.height : 1;
  636. options.xMoveDistance =
  637. parseInt(options.xMoveDistance) > 0 ? options.xMoveDistance : 1;
  638. options.yMoveDistance =
  639. parseInt(options.yMoveDistance) > 0 ? options.yMoveDistance : 1;
  640. let ctx = this.canvas.getContext("2d");
  641.  
  642. let waterImageCanvasArray = [];
  643. let waterImageCanvasDiagonal = parseInt(
  644. Math.sqrt(options.width * options.width + options.height * options.height)
  645. ); /* 水印对角线 */
  646.  
  647. let canvasWidth = this.sizes.width,
  648. /* 画布宽高 */
  649. canvasHeight = this.sizes.height;
  650. let rotateAngle = (options.rotateAngle * Math.PI) / 180; /* 旋转角度 */
  651. let xMoveDistance = options.xMoveDistance; /* 水平移动距离 */
  652. let yMoveDistance = options.yMoveDistance; /* 垂直移动距离 */
  653.  
  654. let centerDrawLeftPosX =
  655. canvasWidth / 2 -
  656. waterImageCanvasDiagonal / 2; /* 中心的绘制水印的左上角坐标x */
  657. let centerDrawLeftPosY =
  658. canvasHeight / 2 -
  659. waterImageCanvasDiagonal / 2; /* 绘制水印的左上角坐标y */
  660. let waterDrawPosX =
  661. (waterImageCanvasDiagonal - options.width) / 2; /* 水印里图片坐标x */
  662. let waterDrawPosY =
  663. (waterImageCanvasDiagonal - options.height) / 2; /* 水印里图片坐标y */
  664.  
  665. Array.from(options.imageArray).forEach((item) => {
  666. /* 先把水印绘制好 */
  667. var waterImageCanvas = document.createElement("canvas");
  668. var waterctx = waterImageCanvas.getContext("2d");
  669.  
  670. waterImageCanvas.width = waterImageCanvasDiagonal;
  671. waterImageCanvas.height = waterImageCanvasDiagonal;
  672. waterctx.globalAlpha = options.globalAlpha; /* 透明度 */
  673. waterctx.translate(
  674. waterImageCanvasDiagonal / 2,
  675. waterImageCanvasDiagonal / 2
  676. );
  677. waterctx.rotate(rotateAngle);
  678. waterctx.translate(
  679. -waterImageCanvasDiagonal / 2,
  680. -waterImageCanvasDiagonal / 2
  681. );
  682. waterctx.drawImage(
  683. item,
  684. waterDrawPosX,
  685. waterDrawPosY,
  686. options.width,
  687. options.height
  688. );
  689.  
  690. waterImageCanvasArray = waterImageCanvasArray.concat(waterImageCanvas);
  691. });
  692.  
  693. function randomArrayData(array_data) {
  694. /* 随机项 */
  695. return array_data[Math.floor(Math.random() * array_data.length)];
  696. }
  697. ctx.setTransform(1, 0, 0, 1, 0, 0);
  698. let pos = [];
  699. for (let i = centerDrawLeftPosX; i < canvasWidth; i += xMoveDistance) {
  700. /* 右侧铺满 */
  701. for (let j = centerDrawLeftPosY; j < canvasHeight; j += yMoveDistance) {
  702. /* 右下 */
  703. if (!checkInArrayByPos(pos, i, j)) {
  704. pos = pos.concat({
  705. x: i,
  706. y: j,
  707. });
  708. ctx.drawImage(
  709. randomArrayData(waterImageCanvasArray),
  710. i,
  711. j
  712. ); /* 绘制水印 */
  713. }
  714. }
  715. for (
  716. let k = centerDrawLeftPosY;
  717. k > -Math.abs(waterImageCanvasDiagonal);
  718. k -= yMoveDistance
  719. ) {
  720. /* 右上 */
  721. if (!checkInArrayByPos(pos, i, k)) {
  722. pos = pos.concat({
  723. x: i,
  724. y: k,
  725. });
  726. ctx.drawImage(randomArrayData(waterImageCanvasArray), i, k);
  727. }
  728. }
  729. }
  730. for (
  731. let i = centerDrawLeftPosX;
  732. i > -Math.abs(waterImageCanvasDiagonal);
  733. i -= xMoveDistance
  734. ) {
  735. /* 左侧铺满 */
  736. for (let j = centerDrawLeftPosY; j < canvasHeight; j += yMoveDistance) {
  737. /* 左下 */
  738. if (!checkInArrayByPos(pos, i, j)) {
  739. pos = pos.concat({
  740. x: i,
  741. y: j,
  742. });
  743. ctx.drawImage(randomArrayData(waterImageCanvasArray), i, j);
  744. }
  745. }
  746. for (
  747. let k = centerDrawLeftPosY;
  748. k > -Math.abs(waterImageCanvasDiagonal);
  749. k -= yMoveDistance
  750. ) {
  751. /* 左上 */
  752. if (!checkInArrayByPos(pos, i, k)) {
  753. pos = pos.concat({
  754. x: i,
  755. y: k,
  756. });
  757. ctx.drawImage(randomArrayData(waterImageCanvasArray), i, k);
  758. }
  759. }
  760. }
  761. };
  762.  
  763. /**
  764. * 获得原图
  765. * @returns {?string}
  766. */
  767. Watermark.prototype.getPreview = function () {
  768. return this.dataUrl;
  769. };
  770.  
  771. /**
  772. * 绘制图片
  773. * @param {string} type png|jpeg
  774. * @returns
  775. */
  776. Watermark.prototype.render = function (type) {
  777. type = type === "png" ? "png" : "jpeg";
  778. return this.canvas.toDataURL("image/" + type);
  779. };
  780.  
  781. /**
  782. * 绘制图片Blob Url-异步
  783. * @async
  784. */
  785. Watermark.prototype.renderBlob = function () {
  786. let that = this;
  787. return new Promise((res) => {
  788. that.canvas.toBlob(function (blob) {
  789. res(window.URL.createObjectURL(blob));
  790. });
  791. });
  792. };
  793.  
  794. /**
  795. * 释放控制权
  796. * @returns {Watermark}
  797. */
  798. Watermark.prototype.noConflict = function () {
  799. if (window.Watermark) {
  800. delete window.Watermark;
  801. }
  802. if (AnotherWatermark) {
  803. window.Watermark = AnotherWatermark;
  804. }
  805. return Watermark;
  806. };
  807. return Watermark;
  808. });