起源:最近小程序需要涉及到一些推广方面的功能,所以要写一个动态生成二维码用户进行下载分享,写完之后受益良多,特此来分享一下;

一.微信小程序动态生成保存二维码

wxml:

  1. <view class='second-code'>
  2. <view class="img-box">
  3. <image bindtap="previewImg" mode="scaleToFill" src="{{imagePath}}"></image>
  4. </view>
  5. <view class="canvas-box">
  6. <canvas hidden="{{canvasHidden}}" style="width: 350rpx;height: 350rpx;" canvas-id="mycanvas"/>
  7. </view>
  8. <text class='downCode' bindtap='downloadCode'>点击下载二维码</text>
    </view>

wxss:

  1. .content-car-second .second-code {
  2. display: flex;
  3. flex-direction: column;
  4. align-items: center;
  5. margin: auto;
  6. position: relative;
  7. }
  8.  
  9. .content-car-second .second-code image {
  10. width: 350rpx;
  11. height: 350rpx;
  12. margin-top: 20rpx;
  13. }
  14.  
  15. .canvas-box{position: fixed;top:999999rpx;left:}

js:

  1. var QR = require("../../utils/qrcode.js");
  2.  
  3. Page({
  4.  
  5. data: {
  6. name:"lishi",
  7. canvasHidden: false,
  8. imagePath: '',
  9. placeholder: 'https://www.xxxxx.com/xxxxx/index.html?name=lishi'//默认二维码生成文本
  10. },
  11.  
  12. //动态生成二维码
  13. onLoad: function (options) {
  14. // 页面初始化 options为页面跳转所带来的参数
  15. var size = this.setCanvasSize();//动态设置画布大小
  16. var initUrl = this.data.placeholder;
  17. this.createQrCode(initUrl, "mycanvas", size.w, size.h);
  18. },
  19.  
  20. //适配不同屏幕大小的canvas
  21. setCanvasSize: function () {
  22. var size = {};
  23. try {
  24. var res = wx.getSystemInfoSync();
  25. var scale = 750 / 350;//不同屏幕下canvas的适配比例;设计稿是750宽
  26. var width = res.windowWidth / scale;
  27. var height = width;//canvas画布为正方形
  28. size.w = width;
  29. size.h = height;
  30. } catch (e) {
  31. // Do something when catch error
  32. console.log("获取设备信息失败" + e);
  33. }
  34. return size;
  35. },
  36. createQrCode: function (url, canvasId, cavW, cavH) {
  37. //调用插件中的draw方法,绘制二维码图片
  38. QR.api.draw(url, canvasId, cavW, cavH);
  39. setTimeout(() => { this.canvasToTempImage(); }, 1000);
  40. },
  41. //获取临时缓存照片路径,存入data中
  42. canvasToTempImage: function () {
  43. var that = this;
  44. wx.canvasToTempFilePath({
  45. canvasId: 'mycanvas',
  46. success: function (res) {
  47. var tempFilePath = res.tempFilePath;
  48. console.log(tempFilePath);
  49. that.setData({
  50. imagePath: tempFilePath,
  51. // canvasHidden:true
  52. });
  53. },
  54. fail: function (res) {
  55. console.log(res);
  56. }
  57. });
  58. },
  59. //点击图片进行预览,长按保存分享图片
  60. previewImg: function (e) {
  61. var img = this.data.imagePath;
  62. console.log(img);
  63. wx.previewImage({
  64. current: img, // 当前显示图片的http链接
  65. urls: [img] // 需要预览的图片http链接列表
  66. })
  67. },
  68.  
  69. // 下载二维码
    downloadCode: function (res) {
       var filePath = this.data.imagePath
       console.log('下载中' + filePath)
       wx.saveImageToPhotosAlbum({
         filePath: filePath,
         success: function(res) {
           wx.showToast({
              title: '图片保存成功',
              icon: 'success',
              duration: 2000 //持续的时间
           })
         },
         fail: function (err) {
            console.log(err)
            wx.showToast({
            title: '图片保存失败',
            icon: 'none',
            duration: 2000//持续的时间
         })
       }
    })
   }
  1. })

注意:二维码地址和下载图片地址域名需要配置好,其次,这数据是通过接口获取的,博主这里展示写的是死数据;

二.qrcode.js

  1. !(function () {
  2.  
  3. // alignment pattern
  4. var adelta = [
  5. 0, 11, 15, 19, 23, 27, 31,
  6. 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
  7. 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
  8. ];
  9.  
  10. // version block
  11. var vpat = [
  12. 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
  13. 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
  14. 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
  15. 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
  16. 0x541, 0xc69
  17. ];
  18.  
  19. // final format bits with mask: level << 3 | mask
  20. var fmtword = [
  21. 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
  22. 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
  23. 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
  24. 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
  25. ];
  26.  
  27. // 4 per version: number of blocks 1,2; data width; ecc width
  28. var eccblocks = [
  29. 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
  30. 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
  31. 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
  32. 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
  33. 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
  34. 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
  35. 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
  36. 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
  37. 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
  38. 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
  39. 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
  40. 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
  41. 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
  42. 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
  43. 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
  44. 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,
  45. 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,
  46. 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,
  47. 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,
  48. 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,
  49. 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
  50. 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,
  51. 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,
  52. 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,
  53. 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,
  54. 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
  55. 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,
  56. 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,
  57. 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,
  58. 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,
  59. 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,
  60. 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,
  61. 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,
  62. 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
  63. 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,
  64. 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,
  65. 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,
  66. 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,
  67. 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,
  68. 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30
  69. ];
  70.  
  71. // Galois field log table
  72. var glog = [
  73. 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
  74. 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
  75. 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
  76. 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
  77. 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
  78. 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
  79. 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
  80. 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
  81. 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
  82. 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
  83. 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
  84. 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
  85. 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
  86. 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
  87. 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
  88. 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
  89. ];
  90.  
  91. // Galios field exponent table
  92. var gexp = [
  93. 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
  94. 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
  95. 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
  96. 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
  97. 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
  98. 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
  99. 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
  100. 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
  101. 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
  102. 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
  103. 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
  104. 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
  105. 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
  106. 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
  107. 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
  108. 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
  109. ];
  110.  
  111. // Working buffers:
  112. // data input and ecc append, image working buffer, fixed part of image, run lengths for badness
  113. var strinbuf = [], eccbuf = [], qrframe = [], framask = [], rlens = [];
  114. // Control values - width is based on version, last 4 are from table.
  115. var version, width, neccblk1, neccblk2, datablkw, eccblkwid;
  116. var ecclevel = 2;
  117. // set bit to indicate cell in qrframe is immutable. symmetric around diagonal
  118. function setmask(x, y) {
  119. var bt;
  120. if (x > y) {
  121. bt = x;
  122. x = y;
  123. y = bt;
  124. }
  125. // y*y = 1+3+5...
  126. bt = y;
  127. bt *= y;
  128. bt += y;
  129. bt >>= 1;
  130. bt += x;
  131. framask[bt] = 1;
  132. }
  133.  
  134. // enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
  135. function putalign(x, y) {
  136. var j;
  137.  
  138. qrframe[x + width * y] = 1;
  139. for (j = -2; j < 2; j++) {
  140. qrframe[(x + j) + width * (y - 2)] = 1;
  141. qrframe[(x - 2) + width * (y + j + 1)] = 1;
  142. qrframe[(x + 2) + width * (y + j)] = 1;
  143. qrframe[(x + j + 1) + width * (y + 2)] = 1;
  144. }
  145. for (j = 0; j < 2; j++) {
  146. setmask(x - 1, y + j);
  147. setmask(x + 1, y - j);
  148. setmask(x - j, y - 1);
  149. setmask(x + j, y + 1);
  150. }
  151. }
  152.  
  153. //========================================================================
  154. // Reed Solomon error correction
  155. // exponentiation mod N
  156. function modnn(x) {
  157. while (x >= 255) {
  158. x -= 255;
  159. x = (x >> 8) + (x & 255);
  160. }
  161. return x;
  162. }
  163.  
  164. var genpoly = [];
  165.  
  166. // Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
  167. function appendrs(data, dlen, ecbuf, eclen) {
  168. var i, j, fb;
  169.  
  170. for (i = 0; i < eclen; i++)
  171. strinbuf[ecbuf + i] = 0;
  172. for (i = 0; i < dlen; i++) {
  173. fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
  174. if (fb != 255) /* fb term is non-zero */
  175. for (j = 1; j < eclen; j++)
  176. strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
  177. else
  178. for (j = ecbuf; j < ecbuf + eclen; j++)
  179. strinbuf[j] = strinbuf[j + 1];
  180. strinbuf[ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
  181. }
  182. }
  183.  
  184. //========================================================================
  185. // Frame data insert following the path rules
  186.  
  187. // check mask - since symmetrical use half.
  188. function ismasked(x, y) {
  189. var bt;
  190. if (x > y) {
  191. bt = x;
  192. x = y;
  193. y = bt;
  194. }
  195. bt = y;
  196. bt += y * y;
  197. bt >>= 1;
  198. bt += x;
  199. return framask[bt];
  200. }
  201.  
  202. //========================================================================
  203. // Apply the selected mask out of the 8.
  204. function applymask(m) {
  205. var x, y, r3x, r3y;
  206.  
  207. switch (m) {
  208. case 0:
  209. for (y = 0; y < width; y++)
  210. for (x = 0; x < width; x++)
  211. if (!((x + y) & 1) && !ismasked(x, y))
  212. qrframe[x + y * width] ^= 1;
  213. break;
  214. case 1:
  215. for (y = 0; y < width; y++)
  216. for (x = 0; x < width; x++)
  217. if (!(y & 1) && !ismasked(x, y))
  218. qrframe[x + y * width] ^= 1;
  219. break;
  220. case 2:
  221. for (y = 0; y < width; y++)
  222. for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  223. if (r3x == 3)
  224. r3x = 0;
  225. if (!r3x && !ismasked(x, y))
  226. qrframe[x + y * width] ^= 1;
  227. }
  228. break;
  229. case 3:
  230. for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  231. if (r3y == 3)
  232. r3y = 0;
  233. for (r3x = r3y, x = 0; x < width; x++ , r3x++) {
  234. if (r3x == 3)
  235. r3x = 0;
  236. if (!r3x && !ismasked(x, y))
  237. qrframe[x + y * width] ^= 1;
  238. }
  239. }
  240. break;
  241. case 4:
  242. for (y = 0; y < width; y++)
  243. for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++ , r3x++) {
  244. if (r3x == 3) {
  245. r3x = 0;
  246. r3y = !r3y;
  247. }
  248. if (!r3y && !ismasked(x, y))
  249. qrframe[x + y * width] ^= 1;
  250. }
  251. break;
  252. case 5:
  253. for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  254. if (r3y == 3)
  255. r3y = 0;
  256. for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  257. if (r3x == 3)
  258. r3x = 0;
  259. if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y))
  260. qrframe[x + y * width] ^= 1;
  261. }
  262. }
  263. break;
  264. case 6:
  265. for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  266. if (r3y == 3)
  267. r3y = 0;
  268. for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  269. if (r3x == 3)
  270. r3x = 0;
  271. if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y))
  272. qrframe[x + y * width] ^= 1;
  273. }
  274. }
  275. break;
  276. case 7:
  277. for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  278. if (r3y == 3)
  279. r3y = 0;
  280. for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  281. if (r3x == 3)
  282. r3x = 0;
  283. if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y))
  284. qrframe[x + y * width] ^= 1;
  285. }
  286. }
  287. break;
  288. }
  289. return;
  290. }
  291.  
  292. // Badness coefficients.
  293. var N1 = 3, N2 = 3, N3 = 40, N4 = 10;
  294.  
  295. // Using the table of the length of each run, calculate the amount of bad image
  296. // - long runs or those that look like finders; called twice, once each for X and Y
  297. function badruns(length) {
  298. var i;
  299. var runsbad = 0;
  300. for (i = 0; i <= length; i++)
  301. if (rlens[i] >= 5)
  302. runsbad += N1 + rlens[i] - 5;
  303. // BwBBBwB as in finder
  304. for (i = 3; i < length - 1; i += 2)
  305. if (rlens[i - 2] == rlens[i + 2]
  306. && rlens[i + 2] == rlens[i - 1]
  307. && rlens[i - 1] == rlens[i + 1]
  308. && rlens[i - 1] * 3 == rlens[i]
  309. // white around the black pattern? Not part of spec
  310. && (rlens[i - 3] == 0 // beginning
  311. || i + 3 > length // end
  312. || rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)
  313. )
  314. runsbad += N3;
  315. return runsbad;
  316. }
  317.  
  318. // Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
  319. function badcheck() {
  320. var x, y, h, b, b1;
  321. var thisbad = 0;
  322. var bw = 0;
  323.  
  324. // blocks of same color.
  325. for (y = 0; y < width - 1; y++)
  326. for (x = 0; x < width - 1; x++)
  327. if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y]
  328. && qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
  329. || !(qrframe[x + width * y] || qrframe[(x + 1) + width * y]
  330. || qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
  331. thisbad += N2;
  332.  
  333. // X runs
  334. for (y = 0; y < width; y++) {
  335. rlens[0] = 0;
  336. for (h = b = x = 0; x < width; x++) {
  337. if ((b1 = qrframe[x + width * y]) == b)
  338. rlens[h]++;
  339. else
  340. rlens[++h] = 1;
  341. b = b1;
  342. bw += b ? 1 : -1;
  343. }
  344. thisbad += badruns(h);
  345. }
  346.  
  347. // black/white imbalance
  348. if (bw < 0)
  349. bw = -bw;
  350.  
  351. var big = bw;
  352. var count = 0;
  353. big += big << 2;
  354. big <<= 1;
  355. while (big > width * width)
  356. big -= width * width, count++;
  357. thisbad += count * N4;
  358.  
  359. // Y runs
  360. for (x = 0; x < width; x++) {
  361. rlens[0] = 0;
  362. for (h = b = y = 0; y < width; y++) {
  363. if ((b1 = qrframe[x + width * y]) == b)
  364. rlens[h]++;
  365. else
  366. rlens[++h] = 1;
  367. b = b1;
  368. }
  369. thisbad += badruns(h);
  370. }
  371. return thisbad;
  372. }
  373.  
  374. function genframe(instring) {
  375. var x, y, k, t, v, i, j, m;
  376.  
  377. // find the smallest version that fits the string
  378. t = instring.length;
  379. version = 0;
  380. do {
  381. version++;
  382. k = (ecclevel - 1) * 4 + (version - 1) * 16;
  383. neccblk1 = eccblocks[k++];
  384. neccblk2 = eccblocks[k++];
  385. datablkw = eccblocks[k++];
  386. eccblkwid = eccblocks[k];
  387. k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
  388. if (t <= k)
  389. break;
  390. } while (version < 40);
  391.  
  392. // FIXME - insure that it fits insted of being truncated
  393. width = 17 + 4 * version;
  394.  
  395. // allocate, clear and setup data structures
  396. v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  397. for (t = 0; t < v; t++)
  398. eccbuf[t] = 0;
  399. strinbuf = instring.slice(0);
  400.  
  401. for (t = 0; t < width * width; t++)
  402. qrframe[t] = 0;
  403.  
  404. for (t = 0; t < (width * (width + 1) + 1) / 2; t++)
  405. framask[t] = 0;
  406.  
  407. // insert finders - black to frame, white to mask
  408. for (t = 0; t < 3; t++) {
  409. k = 0;
  410. y = 0;
  411. if (t == 1)
  412. k = (width - 7);
  413. if (t == 2)
  414. y = (width - 7);
  415. qrframe[(y + 3) + width * (k + 3)] = 1;
  416. for (x = 0; x < 6; x++) {
  417. qrframe[(y + x) + width * k] = 1;
  418. qrframe[y + width * (k + x + 1)] = 1;
  419. qrframe[(y + 6) + width * (k + x)] = 1;
  420. qrframe[(y + x + 1) + width * (k + 6)] = 1;
  421. }
  422. for (x = 1; x < 5; x++) {
  423. setmask(y + x, k + 1);
  424. setmask(y + 1, k + x + 1);
  425. setmask(y + 5, k + x);
  426. setmask(y + x + 1, k + 5);
  427. }
  428. for (x = 2; x < 4; x++) {
  429. qrframe[(y + x) + width * (k + 2)] = 1;
  430. qrframe[(y + 2) + width * (k + x + 1)] = 1;
  431. qrframe[(y + 4) + width * (k + x)] = 1;
  432. qrframe[(y + x + 1) + width * (k + 4)] = 1;
  433. }
  434. }
  435.  
  436. // alignment blocks
  437. if (version > 1) {
  438. t = adelta[version];
  439. y = width - 7;
  440. for (; ;) {
  441. x = width - 7;
  442. while (x > t - 3) {
  443. putalign(x, y);
  444. if (x < t)
  445. break;
  446. x -= t;
  447. }
  448. if (y <= t + 9)
  449. break;
  450. y -= t;
  451. putalign(6, y);
  452. putalign(y, 6);
  453. }
  454. }
  455.  
  456. // single black
  457. qrframe[8 + width * (width - 8)] = 1;
  458.  
  459. // timing gap - mask only
  460. for (y = 0; y < 7; y++) {
  461. setmask(7, y);
  462. setmask(width - 8, y);
  463. setmask(7, y + width - 7);
  464. }
  465. for (x = 0; x < 8; x++) {
  466. setmask(x, 7);
  467. setmask(x + width - 8, 7);
  468. setmask(x, width - 8);
  469. }
  470.  
  471. // reserve mask-format area
  472. for (x = 0; x < 9; x++)
  473. setmask(x, 8);
  474. for (x = 0; x < 8; x++) {
  475. setmask(x + width - 8, 8);
  476. setmask(8, x);
  477. }
  478. for (y = 0; y < 7; y++)
  479. setmask(8, y + width - 7);
  480.  
  481. // timing row/col
  482. for (x = 0; x < width - 14; x++)
  483. if (x & 1) {
  484. setmask(8 + x, 6);
  485. setmask(6, 8 + x);
  486. }
  487. else {
  488. qrframe[(8 + x) + width * 6] = 1;
  489. qrframe[6 + width * (8 + x)] = 1;
  490. }
  491.  
  492. // version block
  493. if (version > 6) {
  494. t = vpat[version - 7];
  495. k = 17;
  496. for (x = 0; x < 6; x++)
  497. for (y = 0; y < 3; y++ , k--)
  498. if (1 & (k > 11 ? version >> (k - 12) : t >> k)) {
  499. qrframe[(5 - x) + width * (2 - y + width - 11)] = 1;
  500. qrframe[(2 - y + width - 11) + width * (5 - x)] = 1;
  501. }
  502. else {
  503. setmask(5 - x, 2 - y + width - 11);
  504. setmask(2 - y + width - 11, 5 - x);
  505. }
  506. }
  507.  
  508. // sync mask bits - only set above for white spaces, so add in black bits
  509. for (y = 0; y < width; y++)
  510. for (x = 0; x <= y; x++)
  511. if (qrframe[x + width * y])
  512. setmask(x, y);
  513.  
  514. // convert string to bitstream
  515. // 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
  516. v = strinbuf.length;
  517.  
  518. // string to array
  519. for (i = 0; i < v; i++)
  520. eccbuf[i] = strinbuf.charCodeAt(i);
  521. strinbuf = eccbuf.slice(0);
  522.  
  523. // calculate max string length
  524. x = datablkw * (neccblk1 + neccblk2) + neccblk2;
  525. if (v >= x - 2) {
  526. v = x - 2;
  527. if (version > 9)
  528. v--;
  529. }
  530.  
  531. // shift and repack to insert length prefix
  532. i = v;
  533. if (version > 9) {
  534. strinbuf[i + 2] = 0;
  535. strinbuf[i + 3] = 0;
  536. while (i--) {
  537. t = strinbuf[i];
  538. strinbuf[i + 3] |= 255 & (t << 4);
  539. strinbuf[i + 2] = t >> 4;
  540. }
  541. strinbuf[2] |= 255 & (v << 4);
  542. strinbuf[1] = v >> 4;
  543. strinbuf[0] = 0x40 | (v >> 12);
  544. }
  545. else {
  546. strinbuf[i + 1] = 0;
  547. strinbuf[i + 2] = 0;
  548. while (i--) {
  549. t = strinbuf[i];
  550. strinbuf[i + 2] |= 255 & (t << 4);
  551. strinbuf[i + 1] = t >> 4;
  552. }
  553. strinbuf[1] |= 255 & (v << 4);
  554. strinbuf[0] = 0x40 | (v >> 4);
  555. }
  556. // fill to end with pad pattern
  557. i = v + 3 - (version < 10);
  558. while (i < x) {
  559. strinbuf[i++] = 0xec;
  560. // buffer has room if (i == x) break;
  561. strinbuf[i++] = 0x11;
  562. }
  563.  
  564. // calculate and append ECC
  565.  
  566. // calculate generator polynomial
  567. genpoly[0] = 1;
  568. for (i = 0; i < eccblkwid; i++) {
  569. genpoly[i + 1] = 1;
  570. for (j = i; j > 0; j--)
  571. genpoly[j] = genpoly[j]
  572. ? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
  573. genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
  574. }
  575. for (i = 0; i <= eccblkwid; i++)
  576. genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
  577.  
  578. // append ecc to data buffer
  579. k = x;
  580. y = 0;
  581. for (i = 0; i < neccblk1; i++) {
  582. appendrs(y, datablkw, k, eccblkwid);
  583. y += datablkw;
  584. k += eccblkwid;
  585. }
  586. for (i = 0; i < neccblk2; i++) {
  587. appendrs(y, datablkw + 1, k, eccblkwid);
  588. y += datablkw + 1;
  589. k += eccblkwid;
  590. }
  591. // interleave blocks
  592. y = 0;
  593. for (i = 0; i < datablkw; i++) {
  594. for (j = 0; j < neccblk1; j++)
  595. eccbuf[y++] = strinbuf[i + j * datablkw];
  596. for (j = 0; j < neccblk2; j++)
  597. eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  598. }
  599. for (j = 0; j < neccblk2; j++)
  600. eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  601. for (i = 0; i < eccblkwid; i++)
  602. for (j = 0; j < neccblk1 + neccblk2; j++)
  603. eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
  604. strinbuf = eccbuf;
  605.  
  606. // pack bits into frame avoiding masked area.
  607. x = y = width - 1;
  608. k = v = 1; // up, minus
  609. /* inteleaved data and ecc codes */
  610. m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  611. for (i = 0; i < m; i++) {
  612. t = strinbuf[i];
  613. for (j = 0; j < 8; j++ , t <<= 1) {
  614. if (0x80 & t)
  615. qrframe[x + width * y] = 1;
  616. do { // find next fill position
  617. if (v)
  618. x--;
  619. else {
  620. x++;
  621. if (k) {
  622. if (y != 0)
  623. y--;
  624. else {
  625. x -= 2;
  626. k = !k;
  627. if (x == 6) {
  628. x--;
  629. y = 9;
  630. }
  631. }
  632. }
  633. else {
  634. if (y != width - 1)
  635. y++;
  636. else {
  637. x -= 2;
  638. k = !k;
  639. if (x == 6) {
  640. x--;
  641. y -= 8;
  642. }
  643. }
  644. }
  645. }
  646. v = !v;
  647. } while (ismasked(x, y));
  648. }
  649. }
  650.  
  651. // save pre-mask copy of frame
  652. strinbuf = qrframe.slice(0);
  653. t = 0; // best
  654. y = 30000; // demerit
  655. // for instead of while since in original arduino code
  656. // if an early mask was "good enough" it wouldn't try for a better one
  657. // since they get more complex and take longer.
  658. for (k = 0; k < 8; k++) {
  659. applymask(k); // returns black-white imbalance
  660. x = badcheck();
  661. if (x < y) { // current mask better than previous best?
  662. y = x;
  663. t = k;
  664. }
  665. if (t == 7)
  666. break; // don't increment i to a void redoing mask
  667. qrframe = strinbuf.slice(0); // reset for next pass
  668. }
  669. if (t != k) // redo best mask - none good enough, last wasn't t
  670. applymask(t);
  671.  
  672. // add in final mask/ecclevel bytes
  673. y = fmtword[t + ((ecclevel - 1) << 3)];
  674. // low byte
  675. for (k = 0; k < 8; k++ , y >>= 1)
  676. if (y & 1) {
  677. qrframe[(width - 1 - k) + width * 8] = 1;
  678. if (k < 6)
  679. qrframe[8 + width * k] = 1;
  680. else
  681. qrframe[8 + width * (k + 1)] = 1;
  682. }
  683. // high byte
  684. for (k = 0; k < 7; k++ , y >>= 1)
  685. if (y & 1) {
  686. qrframe[8 + width * (width - 7 + k)] = 1;
  687. if (k)
  688. qrframe[(6 - k) + width * 8] = 1;
  689. else
  690. qrframe[7 + width * 8] = 1;
  691. }
  692. return qrframe;
  693. }
  694.  
  695. var _canvas = null;
  696.  
  697. var api = {
  698.  
  699. get ecclevel() {
  700. return ecclevel;
  701. },
  702.  
  703. set ecclevel(val) {
  704. ecclevel = val;
  705. },
  706.  
  707. get size() {
  708. return _size;
  709. },
  710.  
  711. set size(val) {
  712. _size = val
  713. },
  714.  
  715. get canvas() {
  716. return _canvas;
  717. },
  718.  
  719. set canvas(el) {
  720. _canvas = el;
  721. },
  722.  
  723. getFrame: function (string) {
  724. return genframe(string);
  725. },
  726. //这里的utf16to8(str)是对Text中的字符串进行转码,让其支持中文
  727. utf16to8: function (str) {
  728. var out, i, len, c;
  729.  
  730. out = "";
  731. len = str.length;
  732. for (i = 0; i < len; i++) {
  733. c = str.charCodeAt(i);
  734. if ((c >= 0x0001) && (c <= 0x007F)) {
  735. out += str.charAt(i);
  736. } else if (c > 0x07FF) {
  737. out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
  738. out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
  739. out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
  740. } else {
  741. out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
  742. out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
  743. }
  744. }
  745. return out;
  746. },
  747. /**
  748. * 新增$this参数,传入组件的this,兼容在组件中生成
  749. */
  750. draw: function (str, canvas, cavW, cavH, $this, ecc) {
  751. var that = this;
  752. ecclevel = ecc || ecclevel;
  753. canvas = canvas || _canvas;
  754. if (!canvas) {
  755. console.warn('No canvas provided to draw QR code in!')
  756. return;
  757. }
  758.  
  759. var size = Math.min(cavW, cavH);
  760. str = that.utf16to8(str);//增加中文显示
  761.  
  762. var frame = that.getFrame(str),
  763. // 组件中生成qrcode需要绑定this
  764. ctx = wx.createCanvasContext(canvas,$this),
  765. px = Math.round(size / (width + 8));
  766. var roundedSize = px * (width + 8),
  767. offset = Math.floor((size - roundedSize) / 2);
  768. size = roundedSize;
  769. //ctx.clearRect(0, 0, cavW, cavW);
  770. ctx.setFillStyle('#ffffff')
  771. ctx.fillRect(0, 0, cavW, cavW);
  772. ctx.setFillStyle('#000000');
  773. for (var i = 0; i < width; i++) {
  774. for (var j = 0; j < width; j++) {
  775. if (frame[j * width + i]) {
  776. ctx.fillRect(px * (4 + i) + offset, px * (4 + j) + offset, px, px);
  777. }
  778. }
  779. }
  780. ctx.draw();
  781. }
  782. }
  783. module.exports = { api }
  784. // exports.draw = api;
  785.  
  786. })();

注意:qrcode.js需要放入你的微信小程序文件夹里面进行引用,有什么问题欢迎在下方留言,我看到后将会进行回复;

微信小程序动态生成保存二维码的更多相关文章

  1. 微信小程序-携带参数的二维码条形码生成

    demo文件目录 index.js文件 //index.js var wxbarcode = require('../../utils/index.js'); Page({ data: { code: ...

  2. 微信小程序之生成图片分享 二维码分享 canvas绘制

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 添加画布 首先,在小程序里进行绘图操作需要用到<canvas>组件,步骤大致分为以 ...

  3. 重磅消息:微信小程序支持长按二维码进入

    之前微信小程序一般通过以下入口进入: 而用户经常使用“长按二维码”识别应用的功能一直未开放,据酷客多了解,微信安卓6.5.6内测版已经支持长按二维码识别和进入小程序,意味着把小程序二维码分享给朋友,或 ...

  4. 微信小程序(4)--二维码窗口

    微信小程序二维码窗口: <view class="btn" bindtap="powerDrawer" data-statu="open&quo ...

  5. 微信小程序 空白页重定向---二维码扫描第二次进入 不经过onLoad过程解析scene参数,跳转问题

    在刚开始的时候将小程序的入口文件直接指向tabbar 的首页,此时出现问题:二维码扫描,第一次不关闭首页,第二次进入时:不会经过onLoad过程解析scene参数: 官方中解释:tabbar跳转方式触 ...

  6. 小程序入口构造工具&二维码测试工具

    小程序入口构造工具&二维码测试工具 本文将介绍我们小程序中隐藏的两个工具页面.原理虽不复杂,收益却实实在在,或许也能给诸君带来启发. 入口构造工具 痛点 PM&运营 投放链接 PM&a ...

  7. demo:动态生成专属二维码

    在日常生活中,随处可见二维码,那么js如何生成动态的专属二维码?其实,通过"二维码插件"我们可以快速生成二维码.在这,记录一下的生成专属二维码demo,一起来看看jquery.qr ...

  8. 微信小程序生成带参数的二维码 小程序二维码

    我是用php写的 先按照要求生成accesstoken $tokenUrl="https://api.weixin.qq.com/cgi-bin/token?grant_type=clien ...

  9. 微信小程序生成带参数的二维码(小程序码)独家asp.net的服务端c#完整代码

    一)我先用的小程序端的wx.request去调用API,发现竟然是一个坑! wx.request({ url: 'https://api.weixin.qq.com/wxa/getwxacodeunl ...

随机推荐

  1. .NET 调试入门(三)常用的命令

    windbg ANSI Command Tree 1.0 title {"Crash Dump Analysis Checklist"} body {"Crash Dum ...

  2. Linux C++ - IP地址转换函数

    1. 函数用途:数字网络序本地序转换 适用类型:IP地址uint32_t类型.端口号uint16_t类型 #include<netinet/in.h> extern uint32_t nt ...

  3. ASP.NET Core 2 学习笔记(八)URL重写

    路由跟URL 重写的功能性略有不同.路由是将Request 找到对应的服务,而URL 重写是为了推卸责任转送Request.本篇将简单介绍下ASP.NET Core的URL重写(URL Rewrite ...

  4. C#一些代码小结--文件对话框

    C# 一些代码小结--文件对话框 查看文件完整路径 try { Config cfg = new Config(); var file = ""; if (saveFileDial ...

  5. 附2 volatile

    注:在阅读本章之前,先要了解Java内存模型,见上一章<附1 Java内存模型与共享变量可见性>,链接如下: http://www.cnblogs.com/java-zhao/p/5124 ...

  6. [LeetCode] Minimum Number of K Consecutive Bit Flips 连续K位翻转的最小次数

    In an array A containing only 0s and 1s, a K-bit flip consists of choosing a (contiguous) subarray o ...

  7. *p++与(*p)++与*(p++)------自增运算符常见误区

    自增运算符(++) 自增\自减运算符分为前缀形(++a)和后缀形(a++),这里重点分析自增 大部分人对前缀和后缀的理解一般是,前缀形式是先++再使用(先变后用),后缀形式是先使用再++(先用后变) ...

  8. Smarty的原理_面试

    Smarty是一个模板引擎,使用smarty主要是为了实现逻辑和外在内容的分离,如果不使用模板的话,通常的做法就是php代码和html代码混编.使用了模板后,则可以将业务逻辑放到php文件中,而负责显 ...

  9. 如何实现keep-alive

    路径: 由上图可知,keep-alive.js导出的对象(如下),作为一个属性将会注入到Vue.options.components中. const patternTypes = [String, R ...

  10. [转][SQL]如何实现存储过程中动态加入条件---没想到语句可以这么巧妙

    在存储过程过程中,如果要实现Select查询的where子句动态查询,可以用exec ( "select .... where" +@whereStr)这样的方式.但这样的话,感觉 ...