• uniapp js 合成canvas画布


    代码

    1. <script>
    2. export default {
    3. name: 'sharePos',
    4. props: {
    5. // 绘制图片的尺寸
    6. // imageSize: {
    7. // type: Object,
    8. // default: () => {}
    9. // },
    10. // canvas绘制的数据
    11. canvasData: {
    12. type: Array,
    13. default: () => []
    14. },
    15. },
    16. data() {
    17. return {
    18. // 屏幕宽度
    19. screenWidth: 0,
    20. // canvas画布的宽度
    21. width: 0,
    22. // canvas画布的高度
    23. height: 0,
    24. // 当前图片放大倍数 - 清晰度
    25. count: 2,
    26. pxWid: 1
    27. };
    28. },
    29. mounted() {
    30. this.initCanvasUnitToRpx();
    31. },
    32. watch: {
    33. // // 监听是否开始绘制
    34. // isDraw: async function(newVal) {
    35. // console.log('newVAL',newVal)
    36. // if(newVal) {
    37. // this.getSystemInfo();
    38. // }
    39. // }
    40. },
    41. methods: {
    42. initCanvasUnitToRpx() {
    43. uni.getSystemInfo({
    44. success: res => {
    45. // 获取屏幕宽度 计算出 适配的单位换算
    46. let wid = res.windowWidth / 375;
    47. this.pxWid = wid
    48. // this.width = this.imageSize.width * this.count;
    49. // this.height = this.imageSize.height * this.count;
    50. const {
    51. ceil
    52. } = Math;
    53. let renderList =this.canvasData.map(ele => {
    54. let info = {};
    55. if (ele.type == 'rect') {
    56. console.log('ele----------------', ele);
    57. let {
    58. x,
    59. y,
    60. width,
    61. height,
    62. radian_1,
    63. radian_2,
    64. radian_3,
    65. radian_4
    66. } = ele.attr;
    67. console.log('999999999999999', x, y, width, height, radian_1, radian_2,
    68. radian_3, radian_4);
    69. info.x = ceil(x * wid);
    70. info.y = ceil(y * wid);
    71. info.width = ceil(width * wid);
    72. info.height = ceil(height * wid);
    73. info.radian_1 = ceil(radian_1 * wid);
    74. info.radian_2 = ceil(radian_2 * wid);
    75. info.radian_3 = ceil(radian_3 * wid);
    76. info.radian_4 = ceil(radian_4 * wid);
    77. console.log('background*---99999rect', info);
    78. }
    79. if (ele.type == 'image') {
    80. let {
    81. x,
    82. y,
    83. width,
    84. height,
    85. radian_1,
    86. radian_2,
    87. radian_3,
    88. radian_4
    89. } = ele.attr;
    90. info.x = ceil(x * wid);
    91. info.y = ceil(y * wid);
    92. info.width = ceil(width * wid);
    93. info.height = ceil(height * wid);
    94. info.radian_1 = ceil(radian_1 * wid);
    95. info.radian_2 = ceil(radian_2 * wid);
    96. info.radian_3 = ceil(radian_3 * wid);
    97. info.radian_4 = ceil(radian_4 * wid);
    98. console.log('background*---99999', info);
    99. }
    100. if (ele.type == 'text') {
    101. let {
    102. x,
    103. y,
    104. fontSize,
    105. height,
    106. fontH,
    107. maxW,
    108. rowCount
    109. } = ele.attr;
    110. console.log('66666666666666', x, y, fontSize, height, fontH, maxW,
    111. rowCount);
    112. info.x = ceil(x * wid);
    113. info.y = ceil(y * wid);
    114. info.fontSize = ceil(fontSize * wid) + 'px';
    115. info.fontH = ceil(fontH * wid);
    116. info.maxW = ceil(maxW * wid);
    117. // info.rowCount = parseInt(rowCount * wid) >= 1 ? parseInt(rowCount *
    118. // wid) : 1;
    119. console.log('textInfo', info);
    120. }
    121. let result = {};
    122. result.type = ele.type;
    123. let resultAttr = {
    124. ...ele.attr,
    125. ...info
    126. };
    127. result.attr = resultAttr;
    128. return result;
    129. });
    130. console.log('renderList', renderList);
    131. this.getImageByCanvasData(renderList);
    132. }
    133. });
    134. },
    135. /**
    136. * 通过数据绘制图片
    137. * @param {array} data canvas绘制的数组
    138. * 格式:每一项的数据
    139. * { type: 'rect', attr: { color: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
    140. * { type: 'image', attr: { image: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
    141. * { type: 'text', attr: { text: '', x, y, color, size, weight, writingMode } }
    142. * */
    143. async getImageByCanvasData(data) {
    144. console.log('99999', data);
    145. // 获取canvas上下文对象
    146. const context = uni.createCanvasContext('canvas', this);
    147. // 清空画布
    148. // context.clearRect(0, 0, this.width * this.count, this.height * this.count);
    149. for (const item of data) {
    150. // 判断类型
    151. if (item.type === 'rect') {
    152. // 绘制圆边矩形
    153. this.drawRoundRectangular(
    154. context,
    155. item.attr.color,
    156. item.attr.x,
    157. item.attr.y,
    158. item.attr.width,
    159. item.attr.height,
    160. item.attr.radian_1,
    161. item.attr.radian_2,
    162. item.attr.radian_3,
    163. item.attr.radian_4
    164. );
    165. } else if (item.type === 'image' && item.attr.image) {
    166. // 绘制圆边图片
    167. await this.drawRoundImageToCanvas(
    168. context,
    169. item.attr.image,
    170. item.attr.x,
    171. item.attr.y,
    172. item.attr.width,
    173. item.attr.height,
    174. item.attr.radian_1,
    175. item.attr.radian_2,
    176. item.attr.radian_3,
    177. item.attr.radian_4
    178. );
    179. } else if (item.type === 'text' && item.attr.text) {
    180. console.log('text', item);
    181. // 绘制文本
    182. this.drawMoreText(
    183. context,
    184. item.attr.text,
    185. item.attr.color,
    186. item.attr.align,
    187. item.attr.x,
    188. item.attr.y,
    189. item.attr.fontStyle,
    190. item.attr.fontVariant,
    191. item.attr.fontWeight,
    192. item.attr.fontSize,
    193. item.attr.fontFamily,
    194. item.attr.fontH,
    195. item.attr.maxW,
    196. item.attr.rowCount
    197. );
    198. }
    199. }
    200. // 绘制图片
    201. context.draw(false, () => {
    202. uni.canvasToTempFilePath({
    203. canvasId: 'canvas',
    204. x: 0,
    205. y: 0,
    206. width: this.width,
    207. height: this.height,
    208. destWidth: this.width,
    209. height: this.height,
    210. success: res => {
    211. this.$emit('generateImageSuccessful', res.tempFilePath);
    212. }
    213. },
    214. this
    215. );
    216. });
    217. },
    218. /**
    219. * 绘制文本
    220. * @param {string} context Canvase的实例
    221. * @param {string} text 文本内容
    222. * @param {number} x 矩形的x坐标
    223. * @param {number} y 矩形的y坐标
    224. * @param {number} color 文本颜色
    225. * @param {number} size 字体的大小
    226. * @param {string} weight 字体的粗细
    227. * @param {string} writingMode 字体的排列方式 - initial 水平 tb 垂直
    228. * */
    229. drawTextToCanvas(context, text, x, y, color = '#000', size = 16, weight = '400', writingMode = 'initial') {
    230. context.fillStyle = color;
    231. context.font = `normal ${weight} ${size}px sans-serif`;
    232. if (writingMode === 'tb') {
    233. const temp = text.split('');
    234. for (let i = 0; i < temp.length; i++) {
    235. context.fillText(temp[i], x, i * size + y);
    236. }
    237. } else {
    238. // 判断是否有换行符
    239. const temp = text.split('\n');
    240. for (let i = 0; i < temp.length; i++) {
    241. context.fillText(temp[i], x, i * size + y + i * size * 0.2); // i * size * 0.2 增加换行的间距
    242. }
    243. }
    244. },
    245. drawMoreText(ctx, text, color, align, x, y, fontStyle, fontVariant, fontWeight, fontSize, fontFamily, fontH,
    246. maxW, rowCount) {
    247. /**
    248. * 绘制文本
    249. *
    250. * text 文本
    251. * color 文字颜色
    252. * align 对其方式
    253. * x 横坐标
    254. * y 纵坐标
    255. * fontStyle 规定字体样式
    256. * fontVariant 规定字体变体
    257. * fontWeight 规定字体的粗细
    258. * fontSize 规定字号和行高,以像素计。
    259. * fontFamily 规定字体系列
    260. * fontH, 行高
    261. maxW, 最大宽度
    262. rowCount 最多几行
    263. * */
    264. console.log('drawMoreText000000000000', ctx, text, color, align, x, y, fontStyle, fontVariant, fontWeight,
    265. fontSize, fontFamily, fontH, maxW, rowCount);
    266. ctx.textAlign = align; //对其方式 left 左 center居中
    267. ctx.fillStyle = color; //filstyle 文本颜色
    268. ctx.font = `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize} ${fontFamily}`; //字体样式
    269. // 以上代码在fillText执行前调用 否则无效
    270. // 文本处理
    271. let strArr = text.split("");
    272. let row = [];
    273. let temp = "";
    274. for (let i = 0; i < strArr.length; i++) {
    275. if (ctx.measureText(temp).width < maxW) {
    276. temp += strArr[i];
    277. } else {
    278. i--; //这里添加了i-- 是为了防止字符丢失,效果图中有对比
    279. row.push(temp);
    280. temp = "";
    281. }
    282. }
    283. row.push(temp); // row有多少项则就有多少行
    284. //如果数组长度大于2,现在只需要显示两行则只截取前两项,把第二行结尾设置成'...'
    285. console.log("row8888888888888888888888888", row)
    286. if (row.length > rowCount) {
    287. let rowCut = row.slice(0, rowCount);
    288. console.log("rowCut", rowCut, rowCount)
    289. let rowPart = rowCut
    290. let test = "";
    291. let empty = [];
    292. for (let i = 0; i < rowPart.length; i++) {
    293. if (ctx.measureText(test).width < maxW) {
    294. test += rowPart[i];
    295. } else {
    296. break;
    297. }
    298. }
    299. empty.push(test);
    300. let group = empty[0] + "..." //这里只显示两行,超出的用...表示
    301. rowCut.splice(rowCount - 1, 1, group);
    302. row = rowCut;
    303. }
    304. console.log('row111111111111111111111', row);
    305. // 把文本绘制到画布中
    306. for (let i = 0; i < row.length; i++) {
    307. // 一次渲染一行
    308. if (align == 'center') {
    309. ctx.fillText(row[i], Math.ceil(maxW / 2 + x), y + i * fontH, maxW); //字体文案和坐标
    310. // 文字 最大宽度
    311. } else if (align == 'left') {
    312. ctx.fillText(row[i], x, y + i * fontH, maxW);
    313. }else if (align=='right'){
    314. // ctx.textAlign ="right"
    315. //align 为right 时 x 表示靠右的距离
    316. ctx.fillText(row[i],375*this.pxWid-x, y + i * fontH, maxW);
    317. }
    318. }
    319. // 保存当前画布状态
    320. ctx.save();
    321. // 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。
    322. // ctx.draw()
    323. // }, 20)
    324. console.log('pppppppppppppppppppp0000');
    325. },
    326. /**
    327. * 绘制圆边矩形
    328. * @param {string} context Canvase的实例
    329. * @param {string} color 填充的颜色
    330. * @param {number} x 矩形的x坐标
    331. * @param {number} y 矩形的y坐标
    332. * @param {number} width 矩形的宽度
    333. * @param {number} height 矩形的高度
    334. * @param {number} height 图片的高度
    335. * @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
    336. * @param {number} radian_2 弧度大小 - radian_2 右下 的弧度
    337. * @param {number} radian_3 弧度大小 - radian_3 左下 的弧度
    338. * @param {number} radian_4 弧度大小 - radian_4 左上 的弧度
    339. * */
    340. drawRoundRectangular(context, color, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {
    341. context.save();
    342. this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);
    343. context.setFillStyle(color);
    344. context.fill();
    345. context.restore();
    346. },
    347. /**
    348. * 绘制圆角图片
    349. * @param {string} context Canvase的实例
    350. * @param {string} image 图片地址
    351. * @param {number} x 图片的x坐标
    352. * @param {number} y 图片的y坐标
    353. * @param {number} width 图片的宽度
    354. * @param {number} height 图片的高度
    355. * @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
    356. * @param {number} radian_2 弧度大小 - radian_2 右下 的弧度
    357. * @param {number} radian_3 弧度大小 - radian_3 左下 的弧度
    358. * @param {number} radian_4 弧度大小 - radian_4 左上 的弧度
    359. * */
    360. async drawRoundImageToCanvas(context, image, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {
    361. context.save();
    362. console.log('9888888888888888888888', context, image, x, y, width, height, radian_1, radian_2,
    363. radian_3, radian_4);
    364. this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);
    365. context.drawImage(await this.handleNetworkImgaeTransferTempImage(image), x, y, width, height);
    366. context.restore();
    367. },
    368. /**
    369. * 绘制圆边路径
    370. * @param {string} context Canvase的实例
    371. * @param {number} x 图片的x坐标
    372. * @param {number} y 图片的y坐标
    373. * @param {number} width 图片的宽度
    374. * @param {number} height 图片的高度
    375. * @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
    376. * @param {number} radian_2 弧度大小 - radian_2 右下 的弧度
    377. * @param {number} radian_3 弧度大小 - radian_3 左下 的弧度
    378. * @param {number} radian_4 弧度大小 - radian_4 左上 的弧度
    379. * */
    380. drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {
    381. // 设置弧度
    382. radian_2 = radian_2 === -1 ? radian_1 : radian_2;
    383. radian_3 = radian_3 === -1 ? radian_1 : radian_3;
    384. radian_4 = radian_4 === -1 ? radian_1 : radian_4;
    385. console.log('988888888888888888888899999drawRoundPath', context, x, y, width, height, radian_1, radian_2,
    386. radian_3, radian_4);
    387. // 创建路径 - 绘制带圆边的矩形
    388. context.beginPath();
    389. context.moveTo(x + radian_2 / 2 + 4, y);
    390. context.arcTo(x + width, y, x + width, y + height, radian_1);
    391. context.arcTo(x + width, y + height, x, y + height, radian_2);
    392. context.arcTo(x, y + height, x, y, radian_3);
    393. context.arcTo(x, y, x + width, y, radian_4);
    394. // 关闭路径 - 结束绘制
    395. // context.closePath();
    396. context.strokeStyle = "rgba(255,0,0)";
    397. // context.lineWidth = -1;
    398. context.globalAlpha = 0
    399. context.stroke(); //描边
    400. context.clip();
    401. context.globalAlpha = 1
    402. },
    403. /** 将网络图片变成临时图片 */
    404. handleNetworkImgaeTransferTempImage(url) {
    405. return new Promise(resolve => {
    406. if (url.indexOf('http') === 0) {
    407. /* uni.downloadFile({
    408. url,
    409. success: res => {
    410. resolve(res.tempFilePath);
    411. }
    412. }); */
    413. uni.getImageInfo({
    414. src: url,
    415. success: (res)=> {
    416. resolve(res.path);
    417. }
    418. });
    419. // this.$ImgTask.imgTempFilePath['xxxxx']
    420. // this.$ImgTask.imgTempFilePath['xxxxx']=res.data;
    421. } else {
    422. resolve(url);
    423. }
    424. });
    425. }
    426. }
    427. };
    428. script>
    429. <style scoped lang="scss">
    430. .canvas-c {
    431. height: 1200rpx;
    432. width:750rpx;
    433. margin: 0 auto;
    434. }
    435. style>

    数据 canvasData

    1. let imgUrlBg = 'https://img1.baidu.com/it/u=1426516032,2216512802&fm=253&fmt=auto&app=138&f=JPEG?w=730&h=405';
    2. let imgUrl1 = 'https://img2.baidu.com/it/u=3022038635,4257685721&fm=253&fmt=auto&app=138&f=PNG?w=500&h=500';
    3. let imgUrl2 = 'https://img0.baidu.com/it/u=4027294468,2844812981&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500';
    4. let imgUrl3 = 'https://img2.baidu.com/it/u=404036556,908612011&fm=253&fmt=auto&app=138&f=JPEG?w=480&h=800';
    5. let list = [
    6. {
    7. type: 'image',
    8. attr: {
    9. image: imgUrlBg,
    10. x: 0,
    11. y: 0,
    12. width: 375,
    13. height: 800,
    14. radian_1: 0,
    15. radian_2:0,
    16. radian_3: 0,
    17. radian_4: 0
    18. }
    19. },
    20. // { type: 'rect', attr: { color: '#f0f', x: 0, y: 0, width: 375, height: 667, radian_1: 16, radian_2: 16, radian_3: 16, radian_4: 16 } },
    21. {
    22. type: 'rect',
    23. attr: {
    24. color: '#0ff',
    25. x: 0,
    26. y: 150,
    27. width: 375,
    28. height: 667,
    29. radian_1: 16,
    30. radian_2: 16,
    31. radian_3: 16,
    32. radian_4: 16
    33. }
    34. },
    35. {
    36. type: 'image',
    37. attr: {
    38. image: imgUrl2,
    39. x: 117.5,
    40. y: 80,
    41. width: 140,
    42. height: 140,
    43. radian_1: 16,
    44. radian_2: 16,
    45. radian_3: 24,
    46. radian_4: 16
    47. }
    48. },
    49. // { type: 'text', attr: { text: '略略大魔王', x: 100, y: 100, color: '#fff', size: 20, weight: '500', writingMode: 'tb' } },
    50. {
    51. type: 'text',
    52. attr: {
    53. text: '一马当先',
    54. color: '#000',
    55. align: 'center',
    56. x: 0,
    57. y: 260,
    58. fontStyle: 'normal',
    59. fontVariant: 'normal',
    60. fontWeight: 'bold',
    61. fontSize: 24,
    62. fontFamily: 'arial',
    63. fontH: 20,
    64. maxW: 375,
    65. rowCount: 1
    66. }
    67. },
    68. {
    69. type: 'text',
    70. attr: {
    71. text: '欢迎来到万马世界',
    72. color: '#000',
    73. align: 'center',
    74. x: 10,
    75. y: 290,
    76. fontStyle: 'normal',
    77. fontVariant: 'normal',
    78. fontWeight: 'normal',
    79. fontSize: 16,
    80. fontFamily: 'arial',
    81. fontH: 20,
    82. maxW: 375,
    83. rowCount: 1
    84. }
    85. },
    86. {
    87. type: 'text',
    88. attr: {
    89. text: '--成就奖励--',
    90. color: '#000',
    91. align: 'center',
    92. x: 10,
    93. y: 320,
    94. fontStyle: 'normal',
    95. fontVariant: 'normal',
    96. fontWeight: 'bold',
    97. fontSize: 14,
    98. fontFamily: 'arial',
    99. fontH: 20,
    100. maxW: 375,
    101. rowCount: 1
    102. }
    103. },
    104. // { type: 'rect', attr: { color: '#fff', x: 0, y: 340, width: 375, height: 120, radian_1: 16, radian_2: 16, radian_3: 16, radian_4: 16 } },
    105. {
    106. type: 'rect',
    107. attr: {
    108. color: '#fff',
    109. x: 0,
    110. y: 350,
    111. width: 375,
    112. height: 120,
    113. radian_1: 16,
    114. radian_2: 16,
    115. radian_3: 16,
    116. radian_4: 16
    117. }
    118. },
    119. {
    120. type: 'text',
    121. attr: {
    122. text: '--成就奖励--',
    123. color: '#000',
    124. align: 'center',
    125. x: 10,
    126. y: 320,
    127. fontStyle: 'normal',
    128. fontVariant: 'normal',
    129. fontWeight: 'bold',
    130. fontSize: 14,
    131. fontFamily: 'arial',
    132. fontH: 20,
    133. maxW: 375,
    134. rowCount: 1
    135. }
    136. },
    137. {
    138. type: 'image',
    139. attr: {
    140. image: imgUrl1,
    141. x: 10,
    142. y: 370,
    143. width: 80,
    144. height: 80,
    145. radian_1: 0,
    146. radian_2: 0,
    147. radian_3: 0,
    148. radian_4: 0
    149. }
    150. },
    151. {
    152. type: 'text',
    153. attr: {
    154. text: '用户的你昵称',
    155. color: '#000',
    156. align: 'left',
    157. x: 100,
    158. y: 390,
    159. fontStyle: 'normal',
    160. fontVariant: 'normal',
    161. fontWeight: 'normal',
    162. fontSize: 16,
    163. fontFamily: 'arial',
    164. fontH: 20,
    165. maxW: 300,
    166. rowCount: 1
    167. }
    168. },
    169. {
    170. type: 'text',
    171. attr: {
    172. text: '累计达成了89个成就',
    173. color: '#000',
    174. align: 'left',
    175. x: 100,
    176. y: 420,
    177. fontStyle: 'normal',
    178. fontVariant: 'normal',
    179. fontWeight: 'normal',
    180. fontSize: 16,
    181. fontFamily: 'arial',
    182. fontH: 20,
    183. maxW: 300,
    184. rowCount: 1
    185. }
    186. },
    187. {
    188. type: 'image',
    189. attr: {
    190. image: imgUrl3,
    191. x: 220,
    192. y: 500,
    193. width: 80,
    194. height: 80,
    195. radian_1: 5,
    196. radian_2: 5,
    197. radian_3: 5,
    198. radian_4: 5
    199. }
    200. },
    201. {
    202. type: 'text',
    203. attr: {
    204. text: '欢迎来到万马世界欢迎来到万马世界欢迎',
    205. color: '#f00',
    206. align: 'right',// left 左 center居中 right 右
    207. x: 20,
    208. y: 20,
    209. fontStyle: 'normal',
    210. fontVariant: 'normal',
    211. fontWeight: 'normal',
    212. fontSize: 16,
    213. fontFamily: 'arial',
    214. fontH: 20,
    215. maxW:200,
    216. rowCount: 3
    217. }
    218. },{
    219. type: 'text',
    220. attr: {
    221. text: '我是谁的谁啊999999999999999999999999999',
    222. color: '#f00',
    223. align: 'right',
    224. x: 0,//align 为right 时 x 表示靠右的距离
    225. y: 560,
    226. fontStyle: 'normal',
    227. fontVariant: 'normal',
    228. fontWeight: 'normal',
    229. fontSize: 16,
    230. fontFamily: 'arial',
    231. fontH: 20,
    232. maxW:100,
    233. rowCount: 3,
    234. }
    235. },
    236. ];
    237. export default list

  • 相关阅读:
    Linux内核有什么之内存管理子系统有什么第五回 —— 小内存分配(3)
    Elasticsearch - Elasticsearch 8.X;Elasticsearch 8.X集群(十)
    110. 平衡二叉树
    UG\NX二次开发 信息窗口的一些操作 NXOpen/ListingWindow
    有没有想过 Java 中的 main 方法为什么一定要用public修饰
    proxmox PVE 安装 黑苹果
    利用STM32 HAL库实现USART串口通信,并通过printf重定向输出“Hello World“
    20.6 OpenSSL 套接字分发RSA公钥
    高考英语语法填空满分秒杀技巧
    AWS 网络
  • 原文地址:https://blog.csdn.net/qq_42389674/article/details/126260970