金诚优选前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1301 lines
37 KiB

  1. import _app from './app.js';
  2. import QRCodeAlg from './QRCodeAlg.js';
  3. const ShreUserPosterBackgroundKey = 'ShrePosterBackground_'; // 背景图片缓存名称前缀
  4. const idKey = 'QSSHAREPOSTER_IDKEY'; //drawArray自动生成的idkey
  5. var isMp = false;
  6. // #ifdef MP
  7. isMp = true;
  8. // #endif
  9. // export default
  10. function getSharePoster(obj) {
  11. return new Promise(async (resolve, reject) => {
  12. try {
  13. const result1 = await returnPromise(obj);
  14. resolve(result1);
  15. } catch (e) {
  16. //TODO handle the exception
  17. removePosterStorage(obj.type);
  18. try {
  19. _app.log('------------清除缓存后, 开始第二次尝试------------');
  20. const result2 = await returnPromise(obj);
  21. resolve(result2);
  22. } catch (e) {
  23. //TODO handle the exception
  24. reject(e);
  25. }
  26. }
  27. })
  28. }
  29. function returnPromise(obj) {
  30. let {
  31. type,
  32. formData,
  33. background,
  34. posterCanvasId,
  35. backgroundImage,
  36. reserve,
  37. textArray,
  38. drawArray,
  39. qrCodeArray,
  40. imagesArray,
  41. setCanvasWH,
  42. setCanvasToTempFilePath,
  43. setDraw,
  44. bgScale,
  45. Context,
  46. _this,
  47. delayTimeScale,
  48. drawDelayTime
  49. } = obj;
  50. return new Promise(async (rs, rj) => {
  51. try {
  52. _app.showLoading('正在准备海报数据');
  53. if (!Context) {
  54. _app.log('没有画布对象,创建画布对象');
  55. Context = uni.createCanvasContext(posterCanvasId, (_this || null));
  56. }
  57. let bgObj;
  58. if (background && background.width && background.height) {
  59. bgObj = background;
  60. } else {
  61. bgObj = await getShreUserPosterBackground({
  62. backgroundImage,
  63. type,
  64. formData
  65. });
  66. }
  67. // 为了ios 缩放一些
  68. bgScale = bgScale || .75;
  69. bgObj.width = bgObj.width * bgScale;
  70. bgObj.height = bgObj.height * bgScale;
  71. _app.log('获取背景图信息对象成功:' + JSON.stringify(bgObj));
  72. const params = {
  73. bgObj,
  74. type,
  75. bgScale
  76. };
  77. if (setCanvasWH && typeof(setCanvasWH) == 'function') {
  78. await new Promise((resolve, reject)=>{
  79. setCanvasWH(params);
  80. setTimeout(()=>{
  81. resolve();
  82. }, 0)
  83. })
  84. }
  85. if (imagesArray) {
  86. if (typeof(imagesArray) == 'function')
  87. imagesArray = imagesArray(params);
  88. _app.showLoading('正在生成需绘制图片的临时路径');
  89. _app.log('准备设置图片');
  90. imagesArray = await setImage(imagesArray);
  91. _app.hideLoading();
  92. }
  93. if (textArray) {
  94. if (typeof(textArray) == 'function')
  95. textArray = textArray(params);
  96. textArray = setText(Context, textArray);
  97. }
  98. if (qrCodeArray) {
  99. if (typeof(qrCodeArray) == 'function')
  100. qrCodeArray = qrCodeArray(params);
  101. _app.showLoading('正在生成需绘制图片的临时路径');
  102. for (let i = 0; i < qrCodeArray.length; i++) {
  103. _app.log(i);
  104. if (qrCodeArray[i].image)
  105. qrCodeArray[i].image = await _app.downloadFile_PromiseFc(qrCodeArray[i].image);
  106. }
  107. _app.hideLoading();
  108. }
  109. if (drawArray) {
  110. if (typeof(drawArray) == 'function') {
  111. drawArray = drawArray(params);
  112. }
  113. if (_app.isPromise(drawArray)) {
  114. drawArray = await drawArray;
  115. }
  116. if (_app.isArray(drawArray) && drawArray.length > 0) {
  117. let hasAllInfoCallback = false;
  118. for (let i = 0; i < drawArray.length; i++) {
  119. const drawArrayItem = drawArray[i];
  120. if (_app.isFn(drawArrayItem.allInfoCallback) && !hasAllInfoCallback) hasAllInfoCallback = true;
  121. drawArrayItem[idKey] = i;
  122. let newData;
  123. switch (drawArrayItem.type) {
  124. case 'image':
  125. newData = await setImage(drawArrayItem);
  126. break;
  127. case 'text':
  128. newData = setText(Context, drawArrayItem);
  129. break;
  130. case 'qrcode':
  131. if (drawArrayItem.image)
  132. newData = {
  133. image: await _app.downloadFile_PromiseFc(drawArrayItem.image)
  134. };
  135. break;
  136. case 'custom':
  137. break;
  138. default:
  139. _app.log('未识别的类型');
  140. break;
  141. }
  142. if (newData && _app.isObject(newData)) {
  143. drawArray[i] = { ...drawArrayItem,
  144. ...newData
  145. }
  146. };
  147. }
  148. if (hasAllInfoCallback) {
  149. _app.log('----------------hasAllInfoCallback----------------');
  150. const drawArray_copy = [...drawArray];
  151. drawArray_copy.sort((a, b) => {
  152. const a_serialNum = !_app.isUndef(a.serialNum) && !_app.isNull(a.serialNum) ? Number(a.serialNum) : Number.NEGATIVE_INFINITY;
  153. const b_serialNum = !_app.isUndef(b.serialNum) && !_app.isNull(b.serialNum) ? Number(b.serialNum) : Number.NEGATIVE_INFINITY;
  154. return a_serialNum - b_serialNum;
  155. })
  156. _app.log('开始for循环');
  157. for (let i = 0; i < drawArray_copy.length; i++) {
  158. const item = { ...drawArray_copy[i]
  159. };
  160. if (_app.isFn(item.allInfoCallback)) {
  161. let newData = item.allInfoCallback({
  162. drawArray: drawArray_copy
  163. });
  164. if (_app.isPromise(newData)) newData = await newData;
  165. const item_idKey = item[idKey];
  166. if (!_app.isUndef(item_idKey)) {
  167. drawArray[item[idKey]] = { ...item,
  168. ...newData
  169. };
  170. } else {
  171. console.log('程序错误 找不到idKey!!! ...这不应该啊');
  172. }
  173. }
  174. }
  175. _app.log('for循环结束');
  176. }
  177. }
  178. }
  179. const poster = await drawShareImage({
  180. Context,
  181. type,
  182. posterCanvasId,
  183. reserve,
  184. drawArray,
  185. textArray,
  186. imagesArray,
  187. bgObj,
  188. qrCodeArray,
  189. setCanvasToTempFilePath,
  190. setDraw,
  191. bgScale,
  192. _this,
  193. delayTimeScale,
  194. drawDelayTime
  195. });
  196. _app.hideLoading();
  197. rs({
  198. bgObj,
  199. poster,
  200. type
  201. });
  202. } catch (e) {
  203. //TODO handle the exception
  204. rj(e);
  205. }
  206. });
  207. }
  208. function drawShareImage(obj) { //绘制海报方法
  209. let {
  210. Context,
  211. type,
  212. posterCanvasId,
  213. reserve,
  214. bgObj,
  215. drawArray,
  216. textArray,
  217. qrCodeArray,
  218. imagesArray,
  219. setCanvasToTempFilePath,
  220. setDraw,
  221. bgScale,
  222. _this,
  223. delayTimeScale,
  224. drawDelayTime
  225. } = obj;
  226. const params = {
  227. Context,
  228. bgObj,
  229. type,
  230. bgScale
  231. };
  232. delayTimeScale = delayTimeScale !== undefined ? delayTimeScale : 15;
  233. drawDelayTime = drawDelayTime !== undefined ? drawDelayTime : 100;
  234. return new Promise((rs, rj) => {
  235. try {
  236. _app.showLoading('正在绘制海报');
  237. _app.log('背景对象:' + JSON.stringify(bgObj));
  238. if (bgObj && bgObj.path) {
  239. _app.log('背景有图片路径');
  240. Context.drawImage(bgObj.path, 0, 0, bgObj.width, bgObj.height);
  241. } else {
  242. _app.log('背景没有图片路径');
  243. if (bgObj.backgroundColor) {
  244. _app.log('背景有背景颜色:' + bgObj.backgroundColor);
  245. Context.setFillStyle(bgObj.backgroundColor);
  246. Context.fillRect(0, 0, bgObj.width, bgObj.height);
  247. } else {
  248. _app.log('背景没有背景颜色');
  249. }
  250. }
  251. _app.showLoading('绘制图片');
  252. if (imagesArray && imagesArray.length > 0)
  253. drawImage(Context, imagesArray);
  254. _app.showLoading('绘制自定义内容');
  255. if (setDraw && typeof(setDraw) == 'function') setDraw(params);
  256. _app.showLoading('绘制文本');
  257. if (textArray && textArray.length > 0)
  258. drawText(Context, textArray, bgObj);
  259. _app.showLoading('绘制二维码');
  260. if (qrCodeArray && qrCodeArray.length > 0) {
  261. for (let i = 0; i < qrCodeArray.length; i++) {
  262. drawQrCode(Context, qrCodeArray[i]);
  263. }
  264. }
  265. _app.showLoading('绘制可控层级序列');
  266. if (drawArray && drawArray.length > 0) {
  267. for (let i = 0; i < drawArray.length; i++) {
  268. const drawArrayItem = drawArray[i];
  269. _app.log('绘制可控层级序列, drawArrayItem:' + JSON.stringify(drawArrayItem));
  270. switch (drawArrayItem.type) {
  271. case 'image':
  272. _app.log('绘制可控层级序列, 绘制图片');
  273. drawImage(Context, drawArrayItem);
  274. break;
  275. case 'text':
  276. _app.log('绘制可控层级序列, 绘制文本');
  277. drawText(Context, drawArrayItem, bgObj);
  278. break;
  279. case 'qrcode':
  280. _app.log('绘制可控层级序列, 绘制二维码');
  281. drawQrCode(Context, drawArrayItem);
  282. break;
  283. case 'custom':
  284. _app.log('绘制可控层级序列, 绘制自定义内容');
  285. if (drawArrayItem.setDraw && typeof drawArrayItem.setDraw === 'function')
  286. drawArrayItem.setDraw(Context);
  287. break;
  288. default:
  289. _app.log('未识别的类型');
  290. break;
  291. }
  292. }
  293. }
  294. _app.showLoading('绘制中')
  295. setTimeout(() => {
  296. _app.log('准备执行draw方法')
  297. _app.log('Context:' + Context);
  298. const fn = function(){
  299. _app.showLoading('正在输出图片');
  300. let setObj = setCanvasToTempFilePath || {};
  301. if (setObj && typeof(setObj) == 'function')
  302. setObj = setCanvasToTempFilePath(bgObj, type);
  303. let canvasToTempFilePathFn;
  304. // #ifdef H5
  305. canvasToTempFilePathFn = function() {
  306. _app.hideLoading();
  307. rs({
  308. tempFilePath: document.querySelector(`uni-canvas[canvas-id=${posterCanvasId}]>canvas`).toDataURL(
  309. 'image/jpeg', setObj.quality || .8)
  310. });
  311. }
  312. // #endif
  313. // #ifndef H5
  314. const data = {
  315. x: 0,
  316. y: 0,
  317. width: bgObj.width,
  318. height: bgObj.height,
  319. destWidth: bgObj.width * 2, // 若H5使用这里请不要乘以二
  320. destHeight: bgObj.height * 2, // 若H5使用这里请不要乘以二
  321. quality: .8,
  322. fileType: 'jpg',
  323. ...setObj
  324. };
  325. _app.log('canvasToTempFilePath的data对象:' + JSON.stringify(data));
  326. canvasToTempFilePathFn = function() {
  327. const toTempFilePathObj = { //输出为图片
  328. ...data,
  329. canvasId: posterCanvasId,
  330. success(res) {
  331. _app.hideLoading();
  332. rs(res);
  333. },
  334. fail(err) {
  335. _app.hideLoading();
  336. _app.log('输出图片失败:' + JSON.stringify(err));
  337. rj('输出图片失败:' + JSON.stringify(err))
  338. }
  339. }
  340. uni.canvasToTempFilePath(toTempFilePathObj, _this || null);
  341. }
  342. // #endif
  343. let delayTime = 0;
  344. if (qrCodeArray) {
  345. qrCodeArray.forEach(item => {
  346. if (item.text) {
  347. delayTime += Number(item.text.length);
  348. }
  349. })
  350. }
  351. if (imagesArray) {
  352. imagesArray.forEach(() => {
  353. delayTime += delayTimeScale;
  354. })
  355. }
  356. if (textArray) {
  357. textArray.forEach(() => {
  358. delayTime += delayTimeScale;
  359. })
  360. }
  361. if (drawArray) {
  362. drawArray.forEach(item => {
  363. switch (item.type) {
  364. case 'text':
  365. if (item.text) {
  366. delayTime += item.text.length;
  367. }
  368. break;
  369. default:
  370. delayTime += delayTimeScale;
  371. break;
  372. }
  373. })
  374. }
  375. _app.log('延时系数:' + delayTimeScale);
  376. _app.log('总计延时:' + delayTime);
  377. setTimeout(canvasToTempFilePathFn, delayTime);
  378. }
  379. Context.draw((typeof(reserve) == 'boolean' ? reserve : false), fn);
  380. }, drawDelayTime);
  381. } catch (e) {
  382. //TODO handle the exception
  383. _app.hideLoading();
  384. rj(e);
  385. }
  386. });
  387. }
  388. // export
  389. function setText(Context, texts) { // 设置文本数据
  390. _app.log('进入设置文字方法, texts:' + JSON.stringify(texts));
  391. if (texts && _app.isArray(texts)) {
  392. _app.log('texts是数组');
  393. if (texts.length > 0) {
  394. for (let i = 0; i < texts.length; i++) {
  395. _app.log('字符串信息-初始化之前:' + JSON.stringify(texts[i]));
  396. texts[i] = setTextFn(Context, texts[i]);
  397. }
  398. }
  399. } else {
  400. _app.log('texts是对象');
  401. texts = setTextFn(Context, texts);
  402. }
  403. _app.log('返回texts:' + JSON.stringify(texts));
  404. return texts;
  405. }
  406. function setTextFn(Context, textItem) {
  407. _app.log('进入设置文字方法, textItem:' + JSON.stringify(textItem));
  408. if (_app.isNotNull_string(textItem.text)) {
  409. textItem.text = String(textItem.text);
  410. textItem.alpha = textItem.alpha !== undefined ? textItem.alpha : 1;
  411. textItem.color = textItem.color || 'black';
  412. textItem.size = textItem.size !== undefined ? textItem.size : 10;
  413. textItem.textAlign = textItem.textAlign || 'left';
  414. textItem.textBaseline = textItem.textBaseline || 'middle';
  415. textItem.dx = textItem.dx || 0;
  416. textItem.dy = textItem.dy || 0;
  417. textItem.size = Math.ceil(Number(textItem.size));
  418. _app.log('字符串信息-初始化默认值后:' + JSON.stringify(textItem));
  419. const textLength = countTextLength(Context, {
  420. text: textItem.text,
  421. size: textItem.size
  422. });
  423. _app.log('字符串信息-初始化时的文本长度:' + textLength);
  424. let infoCallBackObj = {};
  425. if (textItem.infoCallBack && typeof(textItem.infoCallBack) === 'function') {
  426. infoCallBackObj = textItem.infoCallBack(textLength);
  427. }
  428. textItem = {
  429. ...textItem,
  430. textLength,
  431. ...infoCallBackObj
  432. }
  433. _app.log('字符串信息-infoCallBack后:' + JSON.stringify(textItem));
  434. }
  435. return textItem;
  436. }
  437. function countTextLength(Context, obj) {
  438. _app.log('计算文字长度, obj:' + JSON.stringify(obj));
  439. const {
  440. text,
  441. size
  442. } = obj;
  443. Context.setFontSize(size);
  444. let textLength;
  445. /* try{
  446. textLength = Context.measureText(text); // 官方文档说 App端自定义组件编译模式暂时不可用measureText方法
  447. }catch(e){
  448. //TODO handle the exception
  449. textLength = {};
  450. } */
  451. textLength = {};
  452. _app.log('measureText计算文字长度, textLength:' + JSON.stringify(textLength));
  453. textLength = textLength && textLength.width ? textLength.width : 0;
  454. if (!textLength) {
  455. let l = 0;
  456. for (let j = 0; j < text.length; j++) {
  457. let t = text.substr(j, 1);
  458. const countL = countStrLength(t);
  459. _app.log('计算文字宽度系数:' + countL);
  460. l += countL;
  461. }
  462. _app.log('文字宽度总系数:' + l);
  463. textLength = l * size;
  464. }
  465. return textLength;
  466. }
  467. //计算字符长度系数
  468. function countStrLength(t) {
  469. let l;
  470. if (/a/.test(t)) {
  471. l = 0.552734375
  472. } else if (/b/.test(t)) {
  473. l = 0.638671875
  474. } else if (/c/.test(t)) {
  475. l = 0.50146484375
  476. } else if (/d/.test(t)) {
  477. l = 0.6396484375
  478. } else if (/e/.test(t)) {
  479. l = 0.5673828125
  480. } else if (/f/.test(t)) {
  481. l = 0.3466796875
  482. } else if (/g/.test(t)) {
  483. l = 0.6396484375
  484. } else if (/h/.test(t)) {
  485. l = 0.61572265625
  486. } else if (/i/.test(t)) {
  487. l = 0.26611328125
  488. } else if (/j/.test(t)) {
  489. l = 0.26708984375
  490. } else if (/k/.test(t)) {
  491. l = 0.54443359375
  492. } else if (/l/.test(t)) {
  493. l = 0.26611328125
  494. } else if (/m/.test(t)) {
  495. l = 0.93701171875
  496. } else if (/n/.test(t)) {
  497. l = 0.6162109375
  498. } else if (/o/.test(t)) {
  499. l = 0.6357421875
  500. } else if (/p/.test(t)) {
  501. l = 0.638671875
  502. } else if (/q/.test(t)) {
  503. l = 0.6396484375
  504. } else if (/r/.test(t)) {
  505. l = 0.3818359375
  506. } else if (/s/.test(t)) {
  507. l = 0.462890625
  508. } else if (/t/.test(t)) {
  509. l = 0.37255859375
  510. } else if (/u/.test(t)) {
  511. l = 0.6162109375
  512. } else if (/v/.test(t)) {
  513. l = 0.52490234375
  514. } else if (/w/.test(t)) {
  515. l = 0.78955078125
  516. } else if (/x/.test(t)) {
  517. l = 0.5068359375
  518. } else if (/y/.test(t)) {
  519. l = 0.529296875
  520. } else if (/z/.test(t)) {
  521. l = 0.49169921875
  522. } else if (/A/.test(t)) {
  523. l = 0.70361328125
  524. } else if (/B/.test(t)) {
  525. l = 0.62744140625
  526. } else if (/C/.test(t)) {
  527. l = 0.6689453125
  528. } else if (/D/.test(t)) {
  529. l = 0.76171875
  530. } else if (/E/.test(t)) {
  531. l = 0.5498046875
  532. } else if (/F/.test(t)) {
  533. l = 0.53125
  534. } else if (/G/.test(t)) {
  535. l = 0.74365234375
  536. } else if (/H/.test(t)) {
  537. l = 0.7734375
  538. } else if (/I/.test(t)) {
  539. l = 0.2939453125
  540. } else if (/J/.test(t)) {
  541. l = 0.39599609375
  542. } else if (/K/.test(t)) {
  543. l = 0.634765625
  544. } else if (/L/.test(t)) {
  545. l = 0.51318359375
  546. } else if (/M/.test(t)) {
  547. l = 0.97705078125
  548. } else if (/N/.test(t)) {
  549. l = 0.81298828125
  550. } else if (/O/.test(t)) {
  551. l = 0.81494140625
  552. } else if (/P/.test(t)) {
  553. l = 0.61181640625
  554. } else if (/Q/.test(t)) {
  555. l = 0.81494140625
  556. } else if (/R/.test(t)) {
  557. l = 0.65283203125
  558. } else if (/S/.test(t)) {
  559. l = 0.5771484375
  560. } else if (/T/.test(t)) {
  561. l = 0.5732421875
  562. } else if (/U/.test(t)) {
  563. l = 0.74658203125
  564. } else if (/V/.test(t)) {
  565. l = 0.67626953125
  566. } else if (/W/.test(t)) {
  567. l = 1.017578125
  568. } else if (/X/.test(t)) {
  569. l = 0.64501953125
  570. } else if (/Y/.test(t)) {
  571. l = 0.603515625
  572. } else if (/Z/.test(t)) {
  573. l = 0.6201171875
  574. } else if (/[0-9]/.test(t)) {
  575. l = 0.58642578125
  576. } else if (/[\u4e00-\u9fa5]/.test(t)) {
  577. l = 1
  578. } else if (/ /.test(t)) {
  579. l = 0.2958984375
  580. } else if (/\`/.test(t)) {
  581. l = 0.294921875
  582. } else if (/\~/.test(t)) {
  583. l = 0.74169921875
  584. } else if (/\!/.test(t)) {
  585. l = 0.3125
  586. } else if (/\@/.test(t)) {
  587. l = 1.03125
  588. } else if (/\#/.test(t)) {
  589. l = 0.63818359375
  590. } else if (/\$/.test(t)) {
  591. l = 0.58642578125
  592. } else if (/\%/.test(t)) {
  593. l = 0.8896484375
  594. } else if (/\^/.test(t)) {
  595. l = 0.74169921875
  596. } else if (/\&/.test(t)) {
  597. l = 0.8701171875
  598. } else if (/\*/.test(t)) {
  599. l = 0.455078125
  600. } else if (/\(/.test(t)) {
  601. l = 0.333984375
  602. } else if (/\)/.test(t)) {
  603. l = 0.333984375
  604. } else if (/\_/.test(t)) {
  605. l = 0.4482421875
  606. } else if (/\-/.test(t)) {
  607. l = 0.4326171875
  608. } else if (/\+/.test(t)) {
  609. l = 0.74169921875
  610. } else if (/\=/.test(t)) {
  611. l = 0.74169921875
  612. } else if (/\|/.test(t)) {
  613. l = 0.26904296875
  614. } else if (/\\/.test(t)) {
  615. l = 0.416015625
  616. } else if (/\[/.test(t)) {
  617. l = 0.333984375
  618. } else if (/\]/.test(t)) {
  619. l = 0.333984375
  620. } else if (/\;/.test(t)) {
  621. l = 0.24072265625
  622. } else if (/\'/.test(t)) {
  623. l = 0.25634765625
  624. } else if (/\,/.test(t)) {
  625. l = 0.24072265625
  626. } else if (/\./.test(t)) {
  627. l = 0.24072265625
  628. } else if (/\//.test(t)) {
  629. l = 0.42724609375
  630. } else if (/\{/.test(t)) {
  631. l = 0.333984375
  632. } else if (/\}/.test(t)) {
  633. l = 0.333984375
  634. } else if (/\:/.test(t)) {
  635. l = 0.24072265625
  636. } else if (/\"/.test(t)) {
  637. l = 0.435546875
  638. } else if (/\</.test(t)) {
  639. l = 0.74169921875
  640. } else if (/\>/.test(t)) {
  641. l = 0.74169921875
  642. } else if (/\?/.test(t)) {
  643. l = 0.48291015625
  644. } else {
  645. l = 1
  646. }
  647. return l;
  648. }
  649. // export
  650. function setImage(images) { // 设置图片数据
  651. _app.log('进入设置图片数据方法');
  652. return new Promise(async (resolve, rejcet) => {
  653. try {
  654. if (images && _app.isArray(images)) {
  655. _app.log('images是一个数组');
  656. for (let i = 0; i < images.length; i++) {
  657. _app.log('设置图片数据循环中:' + i);
  658. images[i] = await setImageFn(images[i]);
  659. }
  660. } else {
  661. _app.log('images是一个对象');
  662. images = await setImageFn(images);
  663. }
  664. resolve(images);
  665. } catch (e) {
  666. //TODO handle the exception
  667. rejcet(e);
  668. }
  669. })
  670. }
  671. function setImageFn(image) {
  672. return new Promise(async (resolve, reject) => {
  673. if (image.url) {
  674. let imgUrl = image.url;
  675. imgUrl = await _app.downloadFile_PromiseFc(imgUrl);
  676. image.url = imgUrl;
  677. const hasinfoCallBack = image.infoCallBack && typeof(image.infoCallBack) === 'function';
  678. let imageInfo = {};
  679. imageInfo = await _app.getImageInfo_PromiseFc(imgUrl);
  680. if (hasinfoCallBack) {
  681. image = {
  682. ...image,
  683. ...image.infoCallBack(imageInfo)
  684. };
  685. }
  686. image.dx = image.dx || 0;
  687. image.dy = image.dy || 0;
  688. image.dWidth = image.dWidth || imageInfo.width;
  689. image.dHeight = image.dHeight || imageInfo.height;
  690. image = {
  691. ...image,
  692. imageInfo
  693. }
  694. }
  695. resolve(image);
  696. })
  697. }
  698. // export
  699. function drawText(Context, textArray, bgObj) { // 先遍历换行再绘制
  700. if (!_app.isArray(textArray)) {
  701. _app.log('遍历文本方法, 不是数组');
  702. textArray = [textArray];
  703. } else {
  704. _app.log('遍历文本方法, 是数组');
  705. }
  706. _app.log('遍历文本方法, textArray:' + JSON.stringify(textArray));
  707. const newArr = [];
  708. if (textArray && textArray.length > 0) {
  709. for (let j = 0; j < textArray.length; j++) {
  710. const textItem = textArray[j];
  711. if (textItem.text && textItem.lineFeed) {
  712. let lineNum = -1,
  713. maxWidth = bgObj.width,
  714. lineHeight = textItem.size,
  715. dx = textItem.dx;
  716. if (_app.isObject(textItem.lineFeed)) {
  717. const lineFeed = textItem.lineFeed;
  718. lineNum = (lineFeed.lineNum !== undefined && typeof(lineFeed.lineNum) === 'number') && lineFeed.lineNum >= 0 ?
  719. lineFeed.lineNum : lineNum;
  720. maxWidth = (lineFeed.maxWidth !== undefined && typeof(lineFeed.maxWidth) === 'number') ? lineFeed.maxWidth :
  721. maxWidth;
  722. lineHeight = (lineFeed.lineHeight !== undefined && typeof(lineFeed.lineHeight) === 'number') ? lineFeed.lineHeight :
  723. lineHeight;
  724. dx = (lineFeed.dx !== undefined && typeof(lineFeed.dx) === 'number') ? lineFeed.dx : dx;
  725. }
  726. const chr = (textItem.text).split("");
  727. let temp = "";
  728. const row = [];
  729. //循环出几行文字组成数组
  730. for (let a = 0, len = chr.length; a < len; a++) {
  731. if (countTextLength(Context, {
  732. text: temp,
  733. size: textItem.size
  734. }) <= maxWidth && countTextLength(Context, {
  735. text: (temp + chr[a]),
  736. size: textItem.size
  737. }) <= maxWidth) {
  738. temp += chr[a];
  739. if (a == (chr.length - 1)) {
  740. row.push(temp);
  741. }
  742. } else {
  743. row.push(temp);
  744. temp = chr[a];
  745. }
  746. }
  747. _app.log('循环出的文本数组:' + JSON.stringify(row));
  748. //只显示几行 变量间距lineHeight 变量行数lineNum
  749. let allNum = (lineNum >= 0 && lineNum < row.length) ? lineNum : row.length;
  750. for (let i = 0; i < allNum; i++) {
  751. let str = row[i];
  752. if (i == (allNum - 1) && allNum < row.length) {
  753. str = str.substring(0, str.length - 1) + '...';
  754. }
  755. const obj = { ...textItem,
  756. text: str,
  757. dx: i === 0 ? textItem.dx : (dx >= 0 ? dx : textItem.dx),
  758. dy: textItem.dy + (i * lineHeight),
  759. textLength: countTextLength(Context, {
  760. text: str,
  761. size: textItem.size
  762. })
  763. };
  764. _app.log('重新组成的文本对象:' + JSON.stringify(obj));
  765. newArr.push(obj);
  766. }
  767. } else {
  768. newArr.push(textItem);
  769. }
  770. }
  771. }
  772. _app.log('绘制文本新数组:' + JSON.stringify(newArr));
  773. drawTexts(Context, newArr);
  774. }
  775. function setFont(textItem = {}) {
  776. if (textItem.font && typeof(textItem.font) === 'string') {
  777. _app.log(textItem.font)
  778. return textItem.font;
  779. } else {
  780. let fontStyle = 'normal';
  781. let fontVariant = 'normal';
  782. let fontWeight = 'normal';
  783. let fontSize = textItem.size || 10;
  784. let fontFamily = 'sans-serif';
  785. fontSize = Math.ceil(Number(fontSize));
  786. if (textItem.fontStyle && typeof(textItem.fontStyle) === 'string')
  787. fontStyle = textItem.fontStyle.trim();
  788. if (textItem.fontVariant && typeof(textItem.fontVariant) === 'string')
  789. fontVariant = textItem.fontVariant.trim();
  790. if (textItem.fontWeight && (typeof(textItem.fontWeight) === 'string' || typeof(textItem.fontWeight) === 'number'))
  791. fontWeight = textItem.fontWeight.trim();
  792. if (textItem.fontFamily && typeof(textItem.fontFamily) === 'string')
  793. fontFamily = textItem.fontFamily.trim();
  794. return fontStyle + ' ' +
  795. fontVariant + ' ' +
  796. fontWeight + ' ' +
  797. fontSize + 'px' + ' ' +
  798. fontFamily;
  799. }
  800. }
  801. function drawTexts(Context, texts) { // 绘制文本
  802. _app.log('准备绘制文本方法, texts:' + JSON.stringify(texts));
  803. if (texts && _app.isArray(texts)) {
  804. _app.log('准备绘制文本方法, 是数组');
  805. if (texts.length > 0) {
  806. for (let i = 0; i < texts.length; i++) {
  807. drawTextFn(Context, texts[i]);
  808. }
  809. }
  810. } else {
  811. _app.log('准备绘制文本方法, 不是数组');
  812. drawTextFn(Context, texts);
  813. }
  814. }
  815. function drawTextFn(Context, textItem) {
  816. _app.log('进入绘制文本方法, textItem:' + JSON.stringify(textItem));
  817. if (textItem && _app.isObject(textItem) && textItem.text) {
  818. Context.font = setFont(textItem);
  819. Context.setFillStyle(textItem.color);
  820. Context.setGlobalAlpha(textItem.alpha);
  821. Context.setTextAlign(textItem.textAlign);
  822. Context.setTextBaseline(textItem.textBaseline);
  823. Context.fillText(textItem.text, textItem.dx, textItem.dy);
  824. if (textItem.lineThrough && _app.isObject(textItem.lineThrough)) {
  825. _app.log('有删除线');
  826. let lineThrough = textItem.lineThrough;
  827. lineThrough.alpha = lineThrough.alpha !== undefined ? lineThrough.alpha : textItem.alpha;
  828. lineThrough.style = lineThrough.style || textItem.color;
  829. lineThrough.width = lineThrough.width !== undefined ? lineThrough.width : textItem.size / 10;
  830. lineThrough.cap = lineThrough.cap !== undefined ? lineThrough.cap : 'butt';
  831. _app.log('删除线对象:' + JSON.stringify(lineThrough));
  832. Context.setGlobalAlpha(lineThrough.alpha);
  833. Context.setStrokeStyle(lineThrough.style);
  834. Context.setLineWidth(lineThrough.width);
  835. Context.setLineCap(lineThrough.cap);
  836. let mx, my;
  837. switch (textItem.textAlign) {
  838. case 'left':
  839. mx = textItem.dx;
  840. break;
  841. case 'center':
  842. mx = textItem.dx - (textItem.textLength) / 2;
  843. break;
  844. default:
  845. mx = textItem.dx - (textItem.textLength);
  846. break;
  847. }
  848. switch (textItem.textBaseline) {
  849. case 'top':
  850. my = textItem.dy + (textItem.size * .5);
  851. break;
  852. case 'middle':
  853. my = textItem.dy;
  854. break;
  855. default:
  856. my = textItem.dy - (textItem.size * .5);
  857. break;
  858. }
  859. Context.beginPath();
  860. Context.moveTo(mx, my);
  861. Context.lineTo(mx + textItem.textLength, my);
  862. Context.stroke();
  863. Context.closePath();
  864. _app.log('删除线完毕');
  865. }
  866. Context.setGlobalAlpha(1);
  867. Context.font = '10px sans-serif';
  868. }
  869. }
  870. // export
  871. function drawImage(Context, images) { // 绘制图片
  872. _app.log('判断图片数据类型:' + JSON.stringify(images))
  873. if (images && _app.isArray(images)) {
  874. if (images.length > 0) {
  875. for (let i = 0; i < images.length; i++) {
  876. readyDrawImageFn(Context, images[i]);
  877. }
  878. }
  879. } else {
  880. readyDrawImageFn(Context, images);
  881. }
  882. }
  883. function readyDrawImageFn(Context, img) {
  884. _app.log('判断绘制图片形状, img:' + JSON.stringify(img));
  885. if (img.url) {
  886. if (img.circleSet) {
  887. drawCircleImage(Context, img);
  888. } else if (img.roundRectSet) {
  889. drawRoundRectImage(Context, img);
  890. } else {
  891. drawImageFn(Context, img);
  892. }
  893. }
  894. }
  895. function drawImageFn(Context, img) {
  896. _app.log('进入绘制默认图片方法, img:' + JSON.stringify(img));
  897. if (img.url) {
  898. const hasAlpha = !_app.isUndef(img.alpha);
  899. img.alpha = Number(!_app.isUndef(img.alpha) ? img.alpha : 1);
  900. Context.setGlobalAlpha(img.alpha);
  901. _app.log('绘制默认图片方法, 有url');
  902. if (img.dWidth && img.dHeight && img.sx && img.sy && img.sWidth && img.sHeight) {
  903. _app.log('绘制默认图片方法, 绘制第一种方案');
  904. Context.drawImage(img.url, img.dx || 0, img.dy || 0,
  905. img.dWidth || false, img.dHeight || false,
  906. img.sx || false, img.sy || false,
  907. img.sWidth || false, img.sHeight || false);
  908. } else if (img.dWidth && img.dHeight) {
  909. _app.log('绘制默认图片方法, 绘制第二种方案');
  910. Context.drawImage(img.url, img.dx || 0, img.dy || 0,
  911. img.dWidth || false, img.dHeight || false);
  912. } else {
  913. _app.log('绘制默认图片方法, 绘制第三种方案');
  914. Context.drawImage(img.url, img.dx || 0, img.dy || 0);
  915. }
  916. if (hasAlpha) {
  917. Context.setGlobalAlpha(1);
  918. }
  919. }
  920. _app.log('绘制默认图片方法, 绘制完毕');
  921. }
  922. function drawCircleImage(Context, obj) {
  923. _app.log('进入绘制圆形图片方法, obj:' + JSON.stringify(obj));
  924. let {
  925. dx,
  926. dy,
  927. dWidth,
  928. dHeight,
  929. circleSet,
  930. imageInfo
  931. } = obj;
  932. let x, y, r;
  933. if (typeof circleSet === 'object') {
  934. x = circleSet.x;
  935. y = circleSet.y;
  936. r = circleSet.r;
  937. }
  938. if (!r) {
  939. let d;
  940. d = dWidth > dHeight ? dHeight : dWidth;
  941. r = d / 2;
  942. }
  943. x = x ? dx + x : (dx || 0) + r;
  944. y = y ? dy + y : (dy || 0) + r;
  945. Context.save();
  946. Context.beginPath();
  947. Context.arc(x, y, r, 0, 2 * Math.PI, false);
  948. Context.closePath();
  949. Context.setGlobalAlpha(0);
  950. Context.fillStyle = '#FFFFFF';
  951. Context.fill();
  952. Context.setGlobalAlpha(1);
  953. Context.clip();
  954. drawImageFn(Context, obj);
  955. _app.log('默认图片绘制完毕');
  956. Context.restore();
  957. }
  958. function drawRoundRectImage(Context, obj) { // 绘制矩形
  959. _app.log('进入绘制矩形图片方法, obj:' + JSON.stringify(obj));
  960. Context.save();
  961. let {
  962. dx,
  963. dy,
  964. dWidth,
  965. dHeight,
  966. roundRectSet,
  967. imageInfo
  968. } = obj;
  969. let r;
  970. if (typeof roundRectSet === 'object') {
  971. r = roundRectSet.r;
  972. }
  973. r = r || dWidth * .1;
  974. if (dWidth < 2 * r) {
  975. r = dWidth / 2;
  976. }
  977. if (dHeight < 2 * r) {
  978. r = dHeight / 2;
  979. }
  980. Context.beginPath();
  981. Context.moveTo(dx + r, dy);
  982. Context.arcTo(dx + dWidth, dy, dx + dWidth, dy + dHeight, r);
  983. Context.arcTo(dx + dWidth, dy + dHeight, dx, dy + dHeight, r);
  984. Context.arcTo(dx, dy + dHeight, dx, dy, r);
  985. Context.arcTo(dx, dy, dx + dWidth, dy, r);
  986. Context.closePath();
  987. Context.setGlobalAlpha(0);
  988. Context.fillStyle = '#FFFFFF';
  989. Context.fill();
  990. Context.setGlobalAlpha(1);
  991. Context.clip();
  992. drawImageFn(Context, obj);
  993. Context.restore();
  994. _app.log('进入绘制矩形图片方法, 绘制完毕');
  995. }
  996. // export
  997. function drawQrCode(Context, qrCodeObj) { //生成二维码方法, 参考了 诗小柒 的二维码生成器代码
  998. _app.log('进入绘制二维码方法')
  999. _app.showLoading('正在生成二维码');
  1000. let qrcodeAlgObjCache = [];
  1001. let options = {
  1002. text: String(qrCodeObj.text || '') || '', // 生成内容
  1003. size: Number(qrCodeObj.size || 0) || 200, // 二维码大小
  1004. background: String(qrCodeObj.background || '') || '#ffffff', // 背景色
  1005. foreground: String(qrCodeObj.foreground || '') || '#000000', // 前景色
  1006. pdground: String(qrCodeObj.pdground || '') || '#000000', // 定位角点颜色
  1007. correctLevel: Number(qrCodeObj.correctLevel || 0) || 3, // 容错级别
  1008. image: String(qrCodeObj.image || '') || '', // 二维码图标
  1009. imageSize: Number(qrCodeObj.imageSize || 0) || 40, // 二维码图标大小
  1010. dx: Number(qrCodeObj.dx || 0) || 0, // x轴距离
  1011. dy: Number(qrCodeObj.dy || 0) || 0 // y轴距离
  1012. }
  1013. let qrCodeAlg = null;
  1014. let d = 0;
  1015. for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
  1016. d = i;
  1017. if (qrcodeAlgObjCache[i].text == options.text && qrcodeAlgObjCache[i].text.correctLevel == options.correctLevel) {
  1018. qrCodeAlg = qrcodeAlgObjCache[i].obj;
  1019. break;
  1020. }
  1021. }
  1022. if (d == l) {
  1023. qrCodeAlg = new QRCodeAlg(options.text, options.correctLevel);
  1024. qrcodeAlgObjCache.push({
  1025. text: options.text,
  1026. correctLevel: options.correctLevel,
  1027. obj: qrCodeAlg
  1028. });
  1029. }
  1030. let getForeGround = function(config) {
  1031. let options = config.options;
  1032. if (options.pdground && (
  1033. (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
  1034. (config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
  1035. (config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
  1036. )) {
  1037. return options.pdground;
  1038. }
  1039. return options.foreground;
  1040. }
  1041. let count = qrCodeAlg.getModuleCount();
  1042. let ratioSize = options.size;
  1043. let ratioImgSize = options.imageSize;
  1044. //计算每个点的长宽
  1045. let tileW = (ratioSize / count).toPrecision(4);
  1046. let tileH = (ratioSize / count).toPrecision(4);
  1047. //绘制
  1048. for (let row = 0; row < count; row++) {
  1049. for (let col = 0; col < count; col++) {
  1050. let w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW));
  1051. let h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW));
  1052. let foreground = getForeGround({
  1053. row: row,
  1054. col: col,
  1055. count: count,
  1056. options: options
  1057. });
  1058. Context.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background);
  1059. Context.fillRect(options.dx + Math.round(col * tileW), options.dy + Math.round(row * tileH), w, h);
  1060. }
  1061. }
  1062. if (options.image) {
  1063. let x = options.dx + Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
  1064. let y = options.dy + Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
  1065. drawRoundedRect(Context, x, y, ratioImgSize, ratioImgSize, 2, 6, true, true)
  1066. Context.drawImage(options.image, x, y, ratioImgSize, ratioImgSize);
  1067. // 画圆角矩形
  1068. function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) {
  1069. ctxi.setLineWidth(lineWidth);
  1070. ctxi.setFillStyle(options.background);
  1071. ctxi.setStrokeStyle(options.background);
  1072. ctxi.beginPath(); // draw top and top right corner
  1073. ctxi.moveTo(x + r, y);
  1074. ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner
  1075. ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner
  1076. ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner
  1077. ctxi.arcTo(x, y, x + r, y, r);
  1078. ctxi.closePath();
  1079. if (fill) {
  1080. ctxi.fill();
  1081. }
  1082. if (stroke) {
  1083. ctxi.stroke();
  1084. }
  1085. }
  1086. }
  1087. _app.log('进入绘制二维码方法完毕')
  1088. _app.hideLoading();
  1089. }
  1090. function getShreUserPosterBackground(objs) { //检查背景图是否存在于本地, 若存在直接返回, 否则调用getShreUserPosterBackgroundFc方法
  1091. let {
  1092. backgroundImage,
  1093. type
  1094. } = objs;
  1095. return new Promise(async (resolve, reject) => {
  1096. try {
  1097. _app.showLoading('正在获取海报背景图');
  1098. let pbg;
  1099. // #ifndef H5
  1100. pbg = getPosterStorage(type);
  1101. // #endif
  1102. // #ifdef H5
  1103. pbg = false;
  1104. // #endif
  1105. _app.log('获取的缓存:' + JSON.stringify(pbg));
  1106. if (pbg && pbg.path && pbg.name) {
  1107. _app.log('海报有缓存, 准备获取后端背景图进行对比');
  1108. const image = await _app.getPosterUrl(objs);
  1109. _app.log('准备对比name是否相同');
  1110. if (pbg.name === _app.fileNameInPath(image)) {
  1111. _app.log('name相同, 判断该背景图是否存在于本地')
  1112. const index = await _app.checkFile_PromiseFc(pbg.path)
  1113. if (index >= 0) {
  1114. _app.log('海报save路径存在, 对比宽高信息, 存储并输出');
  1115. const imageObj = await _app.getImageInfo_PromiseFc(pbg.path);
  1116. let obj = { ...pbg
  1117. };
  1118. if (!pbg.width || !pbg.height || pbg.width !== imageObj.width || pbg.height !== imageObj.height) {
  1119. _app.log('宽高对比不通过, 重新获取');
  1120. const savedFilePath = await getShreUserPosterBackgroundFc(objs, image)
  1121. _app.hideLoading();
  1122. resolve(savedFilePath);
  1123. } else {
  1124. _app.log('宽高对比通过, 再次存储, 并返回路径');
  1125. obj = {
  1126. ...pbg,
  1127. width: imageObj.width,
  1128. height: imageObj.height
  1129. };
  1130. // #ifndef H5
  1131. setPosterStorage(type, { ...obj
  1132. });
  1133. // #endif
  1134. _app.hideLoading();
  1135. resolve(obj);
  1136. }
  1137. } else {
  1138. _app.log('海报save路径不存在, 重新获取海报');
  1139. const savedFilePath = await getShreUserPosterBackgroundFc(objs, image)
  1140. _app.hideLoading();
  1141. resolve(savedFilePath);
  1142. }
  1143. } else {
  1144. _app.log('name不相同, 重新获取海报');
  1145. const savedFilePath = await getShreUserPosterBackgroundFc(objs, image)
  1146. _app.hideLoading();
  1147. resolve(savedFilePath);
  1148. }
  1149. } else {
  1150. _app.log('海报背景图没有缓存, 准备获取海报背景图');
  1151. const savedFilePath = await getShreUserPosterBackgroundFc(objs)
  1152. _app.hideLoading();
  1153. resolve(savedFilePath);
  1154. }
  1155. } catch (e) {
  1156. _app.hideLoading();
  1157. _app.showToast('获取分享用户背景图失败:' + JSON.stringify(e));
  1158. _app.log(JSON.stringify(e));
  1159. reject(e);
  1160. }
  1161. })
  1162. }
  1163. function getPosterStorage(type) {
  1164. return _app.getStorageSync(getStorageKey(type));
  1165. }
  1166. function removePosterStorage(type) {
  1167. const ShreUserPosterBackgroundKey = getStorageKey(type);
  1168. const pbg = _app.getStorageSync(ShreUserPosterBackgroundKey);
  1169. if (pbg && pbg.path) {
  1170. _app.removeSavedFile(pbg.path);
  1171. _app.removeStorageSync(ShreUserPosterBackgroundKey);
  1172. }
  1173. }
  1174. function setPosterStorage(type, data) {
  1175. _app.setStorage(getStorageKey(type), data);
  1176. }
  1177. function getStorageKey(type) {
  1178. return ShreUserPosterBackgroundKey + (type || 'default');
  1179. }
  1180. function getShreUserPosterBackgroundFc(objs, upimage) { //下载并保存背景图方法
  1181. let {
  1182. backgroundImage,
  1183. type
  1184. } = objs;
  1185. _app.log('获取分享背景图, 尝试清空本地数据');
  1186. removePosterStorage(type);
  1187. return new Promise(async (resolve, reject) => {
  1188. try {
  1189. _app.showLoading('正在下载海报背景图');
  1190. if (upimage) {
  1191. _app.log('有从后端获取的背景图片路径');
  1192. _app.log('尝试下载并保存背景图');
  1193. const name = _app.fileNameInPath(upimage);
  1194. const savedFilePath = await _app.downLoadAndSaveFile_PromiseFc(upimage);
  1195. if (savedFilePath) {
  1196. _app.log('下载并保存背景图成功:' + savedFilePath);
  1197. const imageObj = await _app.getImageInfo_PromiseFc(savedFilePath);
  1198. const returnObj = {
  1199. path: savedFilePath,
  1200. width: imageObj.width,
  1201. height: imageObj.height,
  1202. name
  1203. }
  1204. // #ifndef H5
  1205. setPosterStorage(type, { ...returnObj
  1206. });
  1207. // #endif
  1208. _app.hideLoading();
  1209. resolve(returnObj);
  1210. } else {
  1211. _app.hideLoading();
  1212. reject('not find savedFilePath');
  1213. }
  1214. } else {
  1215. _app.log('没有从后端获取的背景图片路径, 尝试从后端获取背景图片路径');
  1216. const image = await _app.getPosterUrl(objs);
  1217. _app.log('尝试下载并保存背景图:' + image);
  1218. const savedFilePath = await _app.downLoadAndSaveFile_PromiseFc(image);
  1219. if (savedFilePath) {
  1220. _app.log('下载并保存背景图成功:' + savedFilePath);
  1221. const imageObj = await _app.getImageInfo_PromiseFc(savedFilePath);
  1222. _app.log('获取图片信息成功');
  1223. const returnObj = {
  1224. path: savedFilePath,
  1225. width: imageObj.width,
  1226. height: imageObj.height,
  1227. name: _app.fileNameInPath(image)
  1228. }
  1229. _app.log('拼接背景图信息对象成功:' + JSON.stringify(returnObj));
  1230. // #ifndef H5
  1231. setPosterStorage(type, { ...returnObj
  1232. });
  1233. // #endif
  1234. _app.hideLoading();
  1235. _app.log('返回背景图信息对象');
  1236. resolve({ ...returnObj
  1237. });
  1238. } else {
  1239. _app.hideLoading();
  1240. reject('not find savedFilePath');
  1241. }
  1242. }
  1243. } catch (e) {
  1244. //TODO handle the exception
  1245. reject(e);
  1246. }
  1247. });
  1248. }
  1249. module.exports = {
  1250. getSharePoster,
  1251. setText,
  1252. setImage,
  1253. drawText,
  1254. drawImage,
  1255. drawQrCode
  1256. }