oxy-uni-ui 1.2.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +512 -343
  3. package/components/common/util.ts +185 -32
  4. package/components/composables/index.ts +1 -0
  5. package/components/composables/usePopover.ts +24 -20
  6. package/components/composables/useVirtualScroll.ts +48 -21
  7. package/components/composables/useWindowResize.ts +35 -0
  8. package/components/oxy-action-sheet/index.scss +24 -11
  9. package/components/oxy-action-sheet/oxy-action-sheet.vue +27 -19
  10. package/components/oxy-action-sheet/types.ts +7 -0
  11. package/components/oxy-backtop/index.scss +4 -4
  12. package/components/oxy-backtop/oxy-backtop.vue +9 -6
  13. package/components/oxy-backtop/types.ts +7 -7
  14. package/components/oxy-badge/index.scss +4 -4
  15. package/components/oxy-badge/oxy-badge.vue +3 -3
  16. package/components/oxy-badge/types.ts +2 -2
  17. package/components/oxy-button/index.scss +5 -5
  18. package/components/oxy-button/oxy-button.vue +5 -1
  19. package/components/oxy-calendar/index.scss +15 -15
  20. package/components/oxy-calendar/oxy-calendar.vue +1 -0
  21. package/components/oxy-calendar/types.ts +5 -0
  22. package/components/oxy-calendar-view/month/index.scss +4 -4
  23. package/components/oxy-calendar-view/month/types.ts +36 -0
  24. package/components/oxy-calendar-view/monthPanel/index.scss +7 -8
  25. package/components/oxy-calendar-view/monthPanel/month-panel.vue +14 -8
  26. package/components/oxy-calendar-view/year/index.scss +5 -5
  27. package/components/oxy-calendar-view/yearPanel/index.scss +4 -4
  28. package/components/oxy-calendar-view/yearPanel/year-panel.vue +21 -5
  29. package/components/oxy-card/index.scss +2 -2
  30. package/components/oxy-cell/index.scss +8 -8
  31. package/components/oxy-checkbox/index.scss +12 -12
  32. package/components/oxy-checkbox-group/index.scss +2 -2
  33. package/components/oxy-circle/oxy-circle.vue +10 -7
  34. package/components/oxy-circle/types.ts +5 -5
  35. package/components/oxy-col/oxy-col.vue +2 -2
  36. package/components/oxy-col-picker/index.scss +4 -4
  37. package/components/oxy-col-picker/oxy-col-picker.vue +6 -5
  38. package/components/oxy-col-picker/types.ts +7 -2
  39. package/components/oxy-collapse/index.scss +2 -2
  40. package/components/oxy-collapse-item/oxy-collapse-item.vue +3 -3
  41. package/components/oxy-corner/index.scss +33 -33
  42. package/components/oxy-count-to/oxy-count-to.vue +3 -3
  43. package/components/oxy-curtain/index.scss +15 -15
  44. package/components/oxy-curtain/oxy-curtain.vue +4 -2
  45. package/components/oxy-curtain/types.ts +6 -1
  46. package/components/oxy-date-strip/oxy-date-strip.vue +2 -2
  47. package/components/oxy-date-strip/types.ts +1 -1
  48. package/components/oxy-date-strip-item/index.scss +3 -3
  49. package/components/oxy-datetime-picker/index.scss +11 -11
  50. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +1 -0
  51. package/components/oxy-datetime-picker/types.ts +5 -0
  52. package/components/oxy-drop-menu/index.scss +5 -5
  53. package/components/oxy-drop-menu/oxy-drop-menu.vue +3 -3
  54. package/components/oxy-drop-menu-item/index.scss +3 -3
  55. package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +4 -3
  56. package/components/oxy-drop-menu-item/types.ts +5 -0
  57. package/components/oxy-echarts/types.ts +6 -0
  58. package/components/oxy-fab/index.scss +8 -8
  59. package/components/oxy-fab/oxy-fab.vue +22 -3
  60. package/components/oxy-file-list/index.scss +30 -29
  61. package/components/oxy-file-list/oxy-file-list.vue +2 -2
  62. package/components/oxy-floating-panel/oxy-floating-panel.vue +13 -9
  63. package/components/oxy-floating-panel/{type.ts → types.ts} +8 -8
  64. package/components/oxy-footer/index.scss +19 -0
  65. package/components/oxy-footer/oxy-footer.vue +78 -0
  66. package/components/oxy-footer/types.ts +17 -0
  67. package/components/oxy-form-item/types.ts +22 -1
  68. package/components/oxy-gap/oxy-gap.vue +2 -2
  69. package/components/oxy-gap/types.ts +2 -2
  70. package/components/oxy-grid/oxy-grid.vue +1 -1
  71. package/components/oxy-grid/types.ts +1 -1
  72. package/components/oxy-grid-item/index.scss +1 -1
  73. package/components/oxy-grid-item/oxy-grid-item.vue +7 -5
  74. package/components/oxy-grid-item/types.ts +1 -1
  75. package/components/oxy-guidance/index.scss +75 -0
  76. package/components/oxy-guidance/oxy-guidance.vue +201 -0
  77. package/components/oxy-guidance/types.ts +33 -0
  78. package/components/oxy-icon/oxy-icon.vue +2 -2
  79. package/components/oxy-icon/types.ts +1 -1
  80. package/components/oxy-img/oxy-img.vue +4 -4
  81. package/components/oxy-img/types.ts +3 -3
  82. package/components/oxy-img-cropper/index.scss +23 -23
  83. package/components/oxy-img-cropper/oxy-img-cropper.vue +97 -52
  84. package/components/oxy-img-cropper/types.ts +2 -2
  85. package/components/oxy-img-lazy/oxy-img-lazy.vue +3 -3
  86. package/components/oxy-img-lazy/types.ts +3 -3
  87. package/components/oxy-index-anchor/index.scss +2 -2
  88. package/components/oxy-index-anchor/oxy-index-anchor.vue +2 -2
  89. package/components/oxy-index-anchor/{type.ts → types.ts} +3 -0
  90. package/components/oxy-index-bar/index.scss +3 -3
  91. package/components/oxy-index-bar/oxy-index-bar.vue +3 -3
  92. package/components/oxy-index-bar/{type.ts → types.ts} +2 -2
  93. package/components/oxy-input/index.scss +1 -1
  94. package/components/oxy-input-number/index.scss +5 -5
  95. package/components/oxy-input-number/oxy-input-number.vue +2 -2
  96. package/components/oxy-input-number/types.ts +3 -2
  97. package/components/oxy-keyboard/index.scss +5 -5
  98. package/components/oxy-keyboard/key/index.scss +3 -3
  99. package/components/oxy-keyboard/key/index.vue +2 -2
  100. package/components/oxy-keyboard/key/types.ts +15 -0
  101. package/components/oxy-keyboard/oxy-keyboard.vue +1 -0
  102. package/components/oxy-keyboard/types.ts +5 -0
  103. package/components/oxy-link/index.scss +2 -2
  104. package/components/oxy-list/oxy-list.vue +4 -3
  105. package/components/oxy-loading/oxy-loading.vue +8 -4
  106. package/components/oxy-loading/types.ts +1 -1
  107. package/components/oxy-loadmore/index.scss +3 -3
  108. package/components/oxy-long-press-menu/index.scss +93 -0
  109. package/components/oxy-long-press-menu/oxy-long-press-menu.vue +338 -0
  110. package/components/oxy-long-press-menu/types.ts +34 -0
  111. package/components/oxy-message-box/index.scss +12 -11
  112. package/components/oxy-message-box/oxy-message-box.vue +9 -2
  113. package/components/oxy-message-box/types.ts +9 -0
  114. package/components/oxy-navbar/index.scss +2 -2
  115. package/components/oxy-navbar/oxy-navbar.vue +58 -13
  116. package/components/oxy-navbar/types.ts +8 -1
  117. package/components/oxy-navbar-capsule/types.ts +3 -0
  118. package/components/oxy-notice-bar/index.scss +3 -3
  119. package/components/oxy-notice-bar/oxy-notice-bar.vue +9 -5
  120. package/components/oxy-notice-bar/types.ts +3 -3
  121. package/components/oxy-notify/index.ts +1 -0
  122. package/components/oxy-notify/oxy-notify.vue +3 -2
  123. package/components/oxy-notify/types.ts +7 -0
  124. package/components/oxy-pagination/index.scss +6 -5
  125. package/components/oxy-password-input/oxy-password-input.vue +2 -2
  126. package/components/oxy-password-input/types.ts +1 -1
  127. package/components/oxy-picker/index.scss +45 -2
  128. package/components/oxy-picker/oxy-picker.vue +100 -14
  129. package/components/oxy-picker/types.ts +29 -1
  130. package/components/oxy-picker-view/index.scss +4 -4
  131. package/components/oxy-picker-view/oxy-picker-view.vue +4 -4
  132. package/components/oxy-popover/index.scss +13 -13
  133. package/components/oxy-popup/index.scss +4 -4
  134. package/components/oxy-popup/oxy-popup.vue +35 -2
  135. package/components/oxy-popup/types.ts +8 -1
  136. package/components/oxy-progress/index.scss +3 -3
  137. package/components/oxy-qrcode/draw.ts +398 -0
  138. package/components/oxy-qrcode/index.scss +2 -0
  139. package/components/oxy-qrcode/oxy-qrcode.vue +124 -0
  140. package/components/oxy-qrcode/qrcode.ts +936 -0
  141. package/components/oxy-qrcode/types.ts +42 -0
  142. package/components/oxy-radio/index.scss +25 -19
  143. package/components/oxy-radio-group/index.scss +2 -2
  144. package/components/oxy-rate/types.ts +4 -4
  145. package/components/oxy-resize/index.scss +2 -2
  146. package/components/oxy-resize/oxy-resize.vue +4 -4
  147. package/components/oxy-resize/types.ts +3 -0
  148. package/components/oxy-rich-text/index.scss +37 -36
  149. package/components/oxy-rich-text/mp-html/card/card.vue +3 -3
  150. package/components/oxy-rich-text/mp-html/mp-html.vue +33 -24
  151. package/components/oxy-rich-text/mp-html/node/node.vue +30 -19
  152. package/components/oxy-rich-text/oxy-rich-text.vue +31 -31
  153. package/components/oxy-rich-text/types.ts +6 -1
  154. package/components/oxy-row/oxy-row.vue +3 -3
  155. package/components/oxy-row/types.ts +1 -1
  156. package/components/oxy-search/index.scss +7 -7
  157. package/components/oxy-segmented/index.scss +19 -16
  158. package/components/oxy-segmented/oxy-segmented.vue +23 -3
  159. package/components/oxy-select/index.scss +213 -89
  160. package/components/oxy-select/oxy-select.vue +106 -58
  161. package/components/oxy-select/types.ts +13 -1
  162. package/components/oxy-select-picker/index.scss +7 -7
  163. package/components/oxy-select-picker/oxy-select-picker.vue +1 -0
  164. package/components/oxy-select-picker/types.ts +2 -0
  165. package/components/oxy-sidebar-item/index.scss +2 -2
  166. package/components/oxy-signature/oxy-signature.vue +18 -10
  167. package/components/oxy-signature/types.ts +106 -13
  168. package/components/oxy-skeleton/index.scss +1 -1
  169. package/components/oxy-skeleton/oxy-skeleton.vue +6 -6
  170. package/components/oxy-skeleton/types.ts +1 -1
  171. package/components/oxy-slider/index.scss +6 -6
  172. package/components/oxy-sort-button/index.scss +8 -8
  173. package/components/oxy-splitter/index.scss +19 -0
  174. package/components/oxy-splitter/oxy-splitter.vue +409 -0
  175. package/components/oxy-splitter/types.ts +75 -0
  176. package/components/oxy-splitter-panel/index.scss +366 -0
  177. package/components/oxy-splitter-panel/oxy-splitter-panel.vue +432 -0
  178. package/components/oxy-splitter-panel/types.ts +63 -0
  179. package/components/oxy-status-tip/index.scss +4 -4
  180. package/components/oxy-status-tip/oxy-status-tip.vue +5 -5
  181. package/components/oxy-status-tip/types.ts +3 -3
  182. package/components/oxy-step/index.scss +16 -16
  183. package/components/oxy-sticky/oxy-sticky.vue +6 -6
  184. package/components/oxy-stream-render/oxy-stream-render.vue +230 -4
  185. package/components/oxy-stream-render/types.ts +4 -1
  186. package/components/oxy-swipe-action/oxy-swipe-action.vue +27 -2
  187. package/components/oxy-swiper/oxy-swiper.vue +6 -6
  188. package/components/oxy-swiper/types.ts +5 -5
  189. package/components/oxy-swiper-nav/index.scss +3 -3
  190. package/components/oxy-switch/index.scss +10 -10
  191. package/components/oxy-switch/oxy-switch.vue +2 -2
  192. package/components/oxy-switch/types.ts +1 -1
  193. package/components/oxy-tab/index.scss +11 -1
  194. package/components/oxy-tabbar/index.scss +2 -2
  195. package/components/oxy-tabbar/oxy-tabbar.vue +39 -10
  196. package/components/oxy-table/index.scss +8 -8
  197. package/components/oxy-table/oxy-table.vue +8 -6
  198. package/components/oxy-table/types.ts +2 -2
  199. package/components/oxy-table-col/index.scss +3 -3
  200. package/components/oxy-table-col/oxy-table-col.vue +3 -3
  201. package/components/oxy-table-col/types.ts +2 -2
  202. package/components/oxy-tabs/index.scss +52 -22
  203. package/components/oxy-tabs/oxy-tabs.vue +53 -19
  204. package/components/oxy-tabs/types.ts +15 -3
  205. package/components/oxy-tag/index.scss +111 -36
  206. package/components/oxy-text/index.scss +5 -1
  207. package/components/oxy-text/oxy-text.vue +76 -7
  208. package/components/oxy-text/types.ts +12 -0
  209. package/components/oxy-textarea/index.scss +6 -6
  210. package/components/oxy-toast/oxy-toast.vue +24 -8
  211. package/components/oxy-tooltip/index.scss +9 -9
  212. package/components/oxy-tree/index.scss +51 -15
  213. package/components/oxy-tree/oxy-tree.vue +13 -9
  214. package/components/oxy-tree/types.ts +12 -9
  215. package/components/oxy-upload/index.scss +23 -23
  216. package/components/oxy-upload/types.ts +2 -2
  217. package/components/oxy-verification-code/index.scss +6 -0
  218. package/components/oxy-verification-code/oxy-verification-code.vue +187 -0
  219. package/components/oxy-verification-code/types.ts +82 -0
  220. package/components/oxy-video-preview/index.scss +4 -4
  221. package/components/oxy-virtual-scroll/index.scss +5 -5
  222. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +11 -7
  223. package/components/oxy-virtual-scroll/types.ts +14 -14
  224. package/components/oxy-voice-player/index.scss +937 -0
  225. package/components/oxy-voice-player/oxy-voice-player.vue +821 -0
  226. package/components/oxy-voice-player/types.ts +567 -0
  227. package/components/oxy-waterfall/oxy-waterfall.vue +6 -6
  228. package/components/oxy-waterfall/types.ts +6 -6
  229. package/components/oxy-watermark/oxy-watermark.vue +35 -13
  230. package/components/oxy-watermark/types.ts +14 -14
  231. package/global.d.ts +4 -0
  232. package/locale/lang/ar-SA.ts +3 -0
  233. package/locale/lang/en-US.ts +3 -0
  234. package/locale/lang/zh-CN.ts +3 -0
  235. package/package.json +97 -1
  236. package/tags.json +1 -1
  237. package/web-types.json +1 -1
  238. package/components/oxy-number-keyboard/index.scss +0 -78
  239. package/components/oxy-number-keyboard/key/index.scss +0 -81
  240. package/components/oxy-number-keyboard/key/index.vue +0 -78
  241. package/components/oxy-number-keyboard/key/types.ts +0 -11
  242. package/components/oxy-number-keyboard/oxy-number-keyboard.vue +0 -151
  243. package/components/oxy-number-keyboard/types.ts +0 -83
  244. package/components/oxy-tree/components/tree-node-content.vue +0 -72
  245. package/components/oxy-tree/index.ts +0 -51
  246. package/oxy-uni-ui.zip +0 -0
@@ -0,0 +1,936 @@
1
+ export type GenerateFrameResult = {
2
+ frameBuffer: Uint8Array
3
+ width: number
4
+ }
5
+
6
+ /**
7
+ * 二维码生成器
8
+ * @description 纯 UTS 实现的二维码生成算法,支持多平台,兼容 uni-app x。核心算法参考 QR Code 标准,支持自定义纠错级别、自动适配内容长度。
9
+ * @version 1.0.0
10
+ * @平台兼容性 App、H5、微信小程序、UTS
11
+ * @注意事项
12
+ * - 仅支持 8bit 字符串内容,不支持数字/字母/汉字等模式优化
13
+ * - 生成结果为二维码点阵数据和宽度,需配合 canvas 绘制
14
+ * - 纠错级别支持 'L'/'M'/'Q'/'H',默认 'L'
15
+ */
16
+
17
+ // 对齐块间距表 - 不同版本二维码的对齐块分布位置
18
+ const ALIGNMENT_DELTA = [
19
+ 0, 11, 15, 19, 23, 27, 31, 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26,
20
+ 26, 26, 28, 28
21
+ ] as number[]
22
+
23
+ // 纠错块参数表 - 每个版本包含4个参数:块数、数据宽度、纠错宽度
24
+ const ECC_BLOCKS = [
25
+ 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17,
26
+ 18, 2, 0, 13, 22, 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, 2, 0, 68, 18, 4,
27
+ 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14,
28
+ 26, 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, 4, 0, 81, 20, 1, 4, 50, 30, 4,
29
+ 4, 22, 28, 3, 8, 12, 24, 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, 3, 1,
30
+ 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19,
31
+ 24, 3, 13, 15, 30, 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, 3, 4, 113,
32
+ 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, 4, 4, 116, 28, 17, 0, 42, 26, 17, 6,
33
+ 22, 28, 19, 6, 16, 30, 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, 6,
34
+ 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, 10, 2, 114, 28, 19, 4, 46,
35
+ 28, 28, 6, 22, 28, 33, 4, 16, 30, 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31,
36
+ 15, 30, 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, 13, 3, 115, 30,
37
+ 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, 17, 1, 115, 30, 14, 21, 46, 28, 29,
38
+ 19, 24, 30, 11, 46, 15, 30, 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41,
39
+ 15, 30, 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, 4, 18, 122,
40
+ 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, 19, 6, 118, 30, 18, 31, 47, 28,
41
+ 34, 34, 24, 30, 20, 61, 15, 30
42
+ ] as number[]
43
+
44
+ // 纠错级别映射表 - 将人类可读的纠错级别映射为内部数值
45
+ const ECC_LEVELS = new Map<string, number>([
46
+ ['L', 1],
47
+ ['M', 0],
48
+ ['Q', 3],
49
+ ['H', 2]
50
+ ])
51
+
52
+ // 最终格式信息掩码表 - 用于格式信息区域的掩码计算(level << 3 | mask)
53
+ const FINAL_FORMAT = [
54
+ 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976 /* L */, 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0 /* M */,
55
+ 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed /* Q */, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b /* H */
56
+ ]
57
+
58
+ // Galois域指数表 - 用于纠错码计算的查找表
59
+ const GALOIS_EXPONENT = [
60
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
61
+ 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
62
+ 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
63
+ 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
64
+ 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
65
+ 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
66
+ 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
67
+ 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
68
+ 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
69
+ 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
70
+ 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
71
+ ]
72
+
73
+ // Galois域对数表 - 用于纠错码计算的反向查找表
74
+ const GALOIS_LOG = [
75
+ 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
76
+ 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
77
+ 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
78
+ 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 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, 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
80
+ 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
81
+ 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
82
+ 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
83
+ 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
84
+ 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
85
+ 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
86
+ ]
87
+
88
+ // 二维码质量评估系数 - 用于计算最佳掩码模式
89
+ // N1: 连续5个及以上同色模块的惩罚分数
90
+ const N1 = 3
91
+ // N2: 2x2同色模块区域的惩罚分数
92
+ const N2 = 3
93
+ // N3: 类似定位图形的图案(1:1:3:1:1)的惩罚分数
94
+ const N3 = 40
95
+ // N4: 黑白模块比例不均衡的惩罚分数
96
+ const N4 = 10
97
+
98
+ // 版本信息掩码表 - 用于在二维码中嵌入版本信息
99
+ const VERSION_BLOCK = [
100
+ 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e,
101
+ 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69
102
+ ]
103
+
104
+ /**
105
+ * 生成二维码点阵
106
+ * @param _str 输入字符串,支持任意文本内容,默认 null 表示空字符串
107
+ * @param ecc 纠错级别,可选 'L' | 'M' | 'Q' | 'H',默认 'L'
108
+ * @returns {GenerateFrameResult} 返回二维码点阵数据和宽度
109
+ */
110
+ export function generateFrame(_str: string | null = null, ecc: string | null = null): GenerateFrameResult {
111
+ // 变量声明区,所有临时变量、缓冲区
112
+ let i: number
113
+ let t: number
114
+ let j: number
115
+ let k: number
116
+ let v: number
117
+ let x: number
118
+ let y: number
119
+ let version: number
120
+ let str = _str == null ? '' : _str
121
+ let width = 0
122
+ // 获取纠错级别数值
123
+ const eccLevel = ECC_LEVELS.get(ecc == null ? 'L' : ecc)!
124
+
125
+ // Data block
126
+ // 数据块、纠错块、块数
127
+ let dataBlock: number
128
+ let eccBlock: number
129
+ let neccBlock1: number
130
+ let neccBlock2: number
131
+
132
+ // Image buffer.
133
+ // 二维码点阵缓冲区 - 先初始化为空数组,后面会重新赋值
134
+ let frameBuffer = new Uint8Array(0)
135
+
136
+ // Fixed part of the image.
137
+ // 点阵掩码缓冲区(标记不可变区域) - 先初始化为空数组,后面会重新赋值
138
+ let frameMask = new Uint8Array(0)
139
+
140
+ // Generator polynomial.
141
+ // 生成多项式缓冲区(纠错码计算用) - 先初始化为空数组,后面会重新赋值
142
+ let polynomial = new Uint8Array(0)
143
+
144
+ // Data input buffer.
145
+ // 数据输入缓冲区 - 先初始化为空数组,后面会重新赋值
146
+ let stringBuffer = new Uint8Array(0)
147
+
148
+ /**
149
+ * 设置掩码位,表示该点为不可变区域(对称处理)
150
+ * @param _x 横坐标
151
+ * @param _y 纵坐标
152
+ */
153
+ function setMask(_x: number, _y: number) {
154
+ let bit: number
155
+ let x = _x
156
+ let y = _y
157
+
158
+ if (x > y) {
159
+ bit = x
160
+ x = y
161
+ y = bit
162
+ }
163
+
164
+ bit = y
165
+ bit *= y
166
+ bit += y
167
+ bit >>= 1
168
+ bit += x
169
+
170
+ frameMask[bit] = 1
171
+ }
172
+
173
+ /**
174
+ * 添加对齐块,设置对应点阵和掩码
175
+ * @param _x 横坐标
176
+ * @param _y 纵坐标
177
+ */
178
+ function addAlignment(_x: number, _y: number) {
179
+ let i: number
180
+ const x = _x
181
+ const y = _y
182
+
183
+ frameBuffer[x + width * y] = 1
184
+
185
+ for (i = -2; i < 2; i++) {
186
+ frameBuffer[x + i + width * (y - 2)] = 1
187
+ frameBuffer[x - 2 + width * (y + i + 1)] = 1
188
+ frameBuffer[x + 2 + width * (y + i)] = 1
189
+ frameBuffer[x + i + 1 + width * (y + 2)] = 1
190
+ }
191
+
192
+ for (i = 0; i < 2; i++) {
193
+ setMask(x - 1, y + i)
194
+ setMask(x + 1, y - i)
195
+ setMask(x - i, y - 1)
196
+ setMask(x + i, y + 1)
197
+ }
198
+
199
+ for (i = 2; i < 4; i++) {
200
+ frameBuffer[x + i + width * (y - 2)] = 1
201
+ frameBuffer[x - 2 + width * (y + i - 1)] = 1
202
+ frameBuffer[x + 2 + width * (y + i - 2)] = 1
203
+ frameBuffer[x - 1 + width * (y + i - 2)] = 1
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Galois 域取模运算
209
+ * @param _x 输入数值
210
+ * @returns {number} 取模结果
211
+ */
212
+ function modN(_x: number): number {
213
+ let x = _x
214
+ while (x >= 255) {
215
+ x -= 255
216
+ x = (x >> 8) + (x & 255)
217
+ }
218
+
219
+ return x
220
+ }
221
+
222
+ /**
223
+ * 计算并追加纠错码到数据块
224
+ * @param _data 数据起始索引
225
+ * @param _dataLength 数据长度
226
+ * @param _ecc 纠错码起始索引
227
+ * @param _eccLength 纠错码长度
228
+ */
229
+ function appendData(_data: number, _dataLength: number, _ecc: number, _eccLength: number) {
230
+ let bit: number
231
+ let i: number
232
+ let j: number
233
+ const data = _data
234
+ const dataLength = _dataLength
235
+ const ecc = _ecc
236
+ const eccLength = _eccLength
237
+
238
+ for (i = 0; i < eccLength; i++) {
239
+ stringBuffer[ecc + i] = 0
240
+ }
241
+
242
+ for (i = 0; i < dataLength; i++) {
243
+ bit = GALOIS_LOG[stringBuffer[data + i] ^ stringBuffer[ecc]]
244
+
245
+ if (bit != 255) {
246
+ for (j = 1; j < eccLength; j++) {
247
+ stringBuffer[ecc + j - 1] = stringBuffer[ecc + j] ^ GALOIS_EXPONENT[modN(bit + polynomial[eccLength - j])]
248
+ }
249
+ } else {
250
+ for (j = ecc; j < ecc + eccLength; j++) {
251
+ stringBuffer[j] = stringBuffer[j + 1]
252
+ }
253
+ }
254
+
255
+ stringBuffer[ecc + eccLength - 1] = bit == 255 ? 0 : GALOIS_EXPONENT[modN(bit + polynomial[0])]
256
+ }
257
+ }
258
+
259
+ /**
260
+ * 判断某点是否为掩码区域
261
+ * @param _x 横坐标
262
+ * @param _y 纵坐标
263
+ * @returns {boolean} 是否为掩码
264
+ */
265
+ function isMasked(_x: number, _y: number): boolean {
266
+ let bit: number
267
+ let x = _x
268
+ let y = _y
269
+
270
+ if (x > y) {
271
+ bit = x
272
+ x = y
273
+ y = bit
274
+ }
275
+
276
+ bit = y
277
+ bit += y * y
278
+ bit >>= 1
279
+ bit += x
280
+ return frameMask[bit] == 1
281
+ }
282
+
283
+ /**
284
+ * 根据 QR Code 标准,应用指定的掩码 pattern
285
+ * @param mask 掩码编号 (0-7)
286
+ */
287
+ function applyMask(mask: number) {
288
+ for (let y = 0; y < width; y++) {
289
+ for (let x = 0; x < width; x++) {
290
+ if (!isMasked(x, y)) {
291
+ let shouldInvert = false
292
+ switch (mask) {
293
+ case 0:
294
+ shouldInvert = (x + y) % 2 == 0
295
+ break
296
+ case 1:
297
+ shouldInvert = y % 2 == 0
298
+ break
299
+ case 2:
300
+ shouldInvert = x % 3 == 0
301
+ break
302
+ case 3:
303
+ shouldInvert = (x + y) % 3 == 0
304
+ break
305
+ case 4:
306
+ shouldInvert = (Math.floor(y / 2) + Math.floor(x / 3)) % 2 == 0
307
+ break
308
+ case 5:
309
+ shouldInvert = ((x * y) % 2) + ((x * y) % 3) == 0
310
+ break
311
+ case 6:
312
+ shouldInvert = (((x * y) % 2) + ((x * y) % 3)) % 2 == 0
313
+ break
314
+ case 7:
315
+ shouldInvert = (((x + y) % 2) + ((x * y) % 3)) % 2 == 0
316
+ break
317
+ }
318
+
319
+ if (shouldInvert) {
320
+ frameBuffer[x + y * width] ^= 1
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+
327
+ /**
328
+ * 计算连续同色块的"坏度"分数
329
+ * @param runLengths
330
+ * @param length 块长度
331
+ * @returns {number} 坏度分数
332
+ */
333
+ function getBadRuns(runLengths: number[], length: number): number {
334
+ let badRuns = 0
335
+ let i: number
336
+
337
+ for (i = 0; i <= length; i++) {
338
+ if (i < runLengths.length && runLengths[i] >= 5) {
339
+ badRuns += N1 + runLengths[i] - 5
340
+ }
341
+ }
342
+
343
+ // FBFFFBF as in finder.
344
+ for (i = 3; i < length - 1; i += 2) {
345
+ // 检查数组索引是否越界
346
+ if (i + 2 >= runLengths.length || i - 3 < 0) {
347
+ continue
348
+ }
349
+
350
+ if (
351
+ runLengths[i - 2] == runLengths[i + 2] &&
352
+ runLengths[i + 2] == runLengths[i - 1] &&
353
+ runLengths[i - 1] == runLengths[i + 1] &&
354
+ runLengths[i - 1] * 3 == runLengths[i] &&
355
+ // Background around the foreground pattern? Not part of the specs.
356
+ (runLengths[i - 3] == 0 || i + 3 > length || runLengths[i - 3] * 3 >= runLengths[i] * 4 || runLengths[i + 3] * 3 >= runLengths[i] * 4)
357
+ ) {
358
+ badRuns += N3
359
+ }
360
+ }
361
+
362
+ return badRuns
363
+ }
364
+
365
+ /**
366
+ * 评估当前二维码点阵的整体"坏度"
367
+ * @returns {number} 坏度分数
368
+ */
369
+ function checkBadness(): number {
370
+ let b: number
371
+ let b1: number
372
+ let bad = 0
373
+ let big: number
374
+ let bw = 0
375
+ let count = 0
376
+ let h: number
377
+ let x: number
378
+ let y: number
379
+ // 优化:在函数内创建badBuffer,避免外部变量的内存泄漏风险
380
+ const badBuffer = new Array<number>(width)
381
+
382
+ // Blocks of same colour.
383
+ for (y = 0; y < width - 1; y++) {
384
+ for (x = 0; x < width - 1; x++) {
385
+ // All foreground colour.
386
+ if (
387
+ (frameBuffer[x + width * y] == 1 &&
388
+ frameBuffer[x + 1 + width * y] == 1 &&
389
+ frameBuffer[x + width * (y + 1)] == 1 &&
390
+ frameBuffer[x + 1 + width * (y + 1)] == 1) ||
391
+ // All background colour.
392
+ (frameBuffer[x + width * y] == 0 &&
393
+ frameBuffer[x + 1 + width * y] == 0 &&
394
+ frameBuffer[x + width * (y + 1)] == 0 &&
395
+ frameBuffer[x + 1 + width * (y + 1)] == 0)
396
+ ) {
397
+ bad += N2
398
+ }
399
+ }
400
+ }
401
+
402
+ // X runs
403
+ for (y = 0; y < width; y++) {
404
+ h = 0
405
+ badBuffer[h] = 0
406
+ b = 0
407
+ for (x = 0; x < width; x++) {
408
+ b1 = frameBuffer[x + width * y]
409
+ if (b1 == b) {
410
+ if (h < badBuffer.length) {
411
+ badBuffer[h]++
412
+ }
413
+ } else {
414
+ h++
415
+
416
+ if (h < badBuffer.length) {
417
+ badBuffer[h] = 1
418
+ }
419
+ }
420
+
421
+ b = b1
422
+ bw += b > 0 ? 1 : -1
423
+ }
424
+
425
+ bad += getBadRuns(badBuffer, h)
426
+ }
427
+
428
+ if (bw < 0) bw = -bw
429
+
430
+ big = bw
431
+ big += big << 2
432
+ big <<= 1
433
+
434
+ while (big > width * width) {
435
+ big -= width * width
436
+ count++
437
+ }
438
+
439
+ bad += count * N4
440
+
441
+ // Y runs.
442
+ for (x = 0; x < width; x++) {
443
+ h = 0
444
+ badBuffer[h] = 0
445
+ b = 0
446
+ for (y = 0; y < width; y++) {
447
+ b1 = frameBuffer[x + width * y]
448
+ if (b1 == b) {
449
+ if (h < badBuffer.length) {
450
+ badBuffer[h]++
451
+ }
452
+ } else {
453
+ h++
454
+ if (h < badBuffer.length) {
455
+ badBuffer[h] = 1
456
+ }
457
+ }
458
+
459
+ b = b1
460
+ }
461
+
462
+ bad += getBadRuns(badBuffer, h)
463
+ }
464
+
465
+ return bad
466
+ }
467
+
468
+ /**
469
+ * 将字符串转为 UTF-8 编码,兼容多平台
470
+ * @param str 输入字符串
471
+ * @returns {string} UTF-8 编码字符串
472
+ */
473
+ function toUtf8(str: string): string {
474
+ let out = ''
475
+ let i: number
476
+ const len: number = str.length
477
+ let c: number
478
+ for (i = 0; i < len; i++) {
479
+ c = str.charCodeAt(i)!
480
+ if (c >= 0x0001 && c <= 0x007f) {
481
+ out += str.charAt(i)
482
+ } else if (c > 0x07ff) {
483
+ out += String.fromCharCode(0xe0 | ((c >> 12) & 0x0f))
484
+ out += String.fromCharCode(0x80 | ((c >> 6) & 0x3f))
485
+ out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f))
486
+ } else {
487
+ out += String.fromCharCode(0xc0 | ((c >> 6) & 0x1f))
488
+ out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f))
489
+ }
490
+ }
491
+ return out
492
+ }
493
+ //end functions
494
+
495
+ // Find the smallest version that fits the string.
496
+ // 1. 字符串转 UTF-8,计算长度
497
+ str = toUtf8(str)
498
+ t = str.length
499
+
500
+ // 2. 自动选择最小可用版本
501
+ version = 0
502
+ do {
503
+ version++
504
+ k = (eccLevel - 1) * 4 + (version - 1) * 16
505
+ neccBlock1 = ECC_BLOCKS[k++]
506
+ neccBlock2 = ECC_BLOCKS[k++]
507
+ dataBlock = ECC_BLOCKS[k++]
508
+ eccBlock = ECC_BLOCKS[k]
509
+
510
+ k = dataBlock * (neccBlock1 + neccBlock2) + neccBlock2 - 3 + (version <= 9 ? 1 : 0)
511
+
512
+ if (t <= k) break
513
+ } while (version < 40)
514
+
515
+ // FIXME: Ensure that it fits insted of being truncated.
516
+ // 3. 计算二维码宽度
517
+ width = 17 + 4 * version
518
+
519
+ // Allocate, clear and setup data structures.
520
+ // 4. 分配缓冲区, 使用定长的 Uint8Array 优化内存
521
+ v = dataBlock + (dataBlock + eccBlock) * (neccBlock1 + neccBlock2) + neccBlock2
522
+ // ECC buffer.
523
+ // 纠错码缓冲区 - 先初始化为空数组,后面会重新赋值
524
+ const eccBuffer: Uint8Array = new Uint8Array(v)
525
+ stringBuffer = new Uint8Array(v)
526
+
527
+ // 5. 预分配点阵、掩码缓冲区
528
+ frameBuffer = new Uint8Array(width * width)
529
+ frameMask = new Uint8Array(Math.floor((width * (width + 1) + 1) / 2))
530
+
531
+ // Insert finders: Foreground colour to frame and background to mask.
532
+ // 插入定位点: 前景色为二维码,背景色为掩码
533
+ for (t = 0; t < 3; t++) {
534
+ k = 0
535
+ y = 0
536
+ if (t == 1) k = width - 7
537
+ if (t == 2) y = width - 7
538
+
539
+ frameBuffer[y + 3 + width * (k + 3)] = 1
540
+
541
+ for (x = 0; x < 6; x++) {
542
+ frameBuffer[y + x + width * k] = 1
543
+ frameBuffer[y + width * (k + x + 1)] = 1
544
+ frameBuffer[y + 6 + width * (k + x)] = 1
545
+ frameBuffer[y + x + 1 + width * (k + 6)] = 1
546
+ }
547
+
548
+ for (x = 1; x < 5; x++) {
549
+ setMask(y + x, k + 1)
550
+ setMask(y + 1, k + x + 1)
551
+ setMask(y + 5, k + x)
552
+ setMask(y + x + 1, k + 5)
553
+ }
554
+
555
+ for (x = 2; x < 4; x++) {
556
+ frameBuffer[y + x + width * (k + 2)] = 1
557
+ frameBuffer[y + 2 + width * (k + x + 1)] = 1
558
+ frameBuffer[y + 4 + width * (k + x)] = 1
559
+ frameBuffer[y + x + 1 + width * (k + 4)] = 1
560
+ }
561
+ }
562
+
563
+ // Alignment blocks.
564
+ // 插入对齐点: 前景色为二维码,背景色为掩码
565
+ if (version > 1) {
566
+ t = ALIGNMENT_DELTA[version]
567
+ y = width - 7
568
+
569
+ for (;;) {
570
+ x = width - 7
571
+
572
+ while (x > t - 3) {
573
+ addAlignment(x, y)
574
+
575
+ if (x < t) break
576
+
577
+ x -= t
578
+ }
579
+
580
+ if (y <= t + 9) break
581
+
582
+ y -= t
583
+
584
+ addAlignment(6, y)
585
+ addAlignment(y, 6)
586
+ }
587
+ }
588
+
589
+ // Single foreground cell.
590
+ // 插入单个前景色单元格: 前景色为二维码,背景色为掩码
591
+ frameBuffer[8 + width * (width - 8)] = 1
592
+
593
+ // Timing gap (mask only).
594
+ // 插入时间间隔: 掩码
595
+ for (y = 0; y < 7; y++) {
596
+ setMask(7, y)
597
+ setMask(width - 8, y)
598
+ setMask(7, y + width - 7)
599
+ }
600
+
601
+ for (x = 0; x < 8; x++) {
602
+ setMask(x, 7)
603
+ setMask(x + width - 8, 7)
604
+ setMask(x, width - 8)
605
+ }
606
+
607
+ // Reserve mask, format area.
608
+ // 保留掩码,格式化区域
609
+ for (x = 0; x < 9; x++) {
610
+ setMask(x, 8)
611
+ }
612
+
613
+ for (x = 0; x < 8; x++) {
614
+ setMask(x + width - 8, 8)
615
+ setMask(8, x)
616
+ }
617
+
618
+ for (y = 0; y < 7; y++) {
619
+ setMask(8, y + width - 7)
620
+ }
621
+
622
+ // Timing row/column.
623
+ // 插入时间间隔行/列: 掩码
624
+ for (x = 0; x < width - 14; x++) {
625
+ if ((x & 1) > 0) {
626
+ setMask(8 + x, 6)
627
+ setMask(6, 8 + x)
628
+ } else {
629
+ frameBuffer[8 + x + width * 6] = 1
630
+ frameBuffer[6 + width * (8 + x)] = 1
631
+ }
632
+ }
633
+
634
+ // Version block.
635
+ if (version > 6) {
636
+ t = VERSION_BLOCK[version - 7]
637
+ k = 17
638
+
639
+ for (x = 0; x < 6; x++) {
640
+ for (y = 0; y < 3; y++) {
641
+ if ((1 & (k > 11 ? version >> (k - 12) : t >> k)) > 0) {
642
+ frameBuffer[5 - x + width * (2 - y + width - 11)] = 1
643
+ frameBuffer[2 - y + width - 11 + width * (5 - x)] = 1
644
+ } else {
645
+ setMask(5 - x, 2 - y + width - 11)
646
+ setMask(2 - y + width - 11, 5 - x)
647
+ }
648
+ k--
649
+ }
650
+ }
651
+ }
652
+
653
+ // Sync mask bits. Only set above for background cells, so now add the foreground.
654
+ // 同步掩码位。只有上方的背景单元格需要设置,现在添加前景色。
655
+ for (y = 0; y < width; y++) {
656
+ for (x = 0; x <= y; x++) {
657
+ if (frameBuffer[x + width * y] > 0) {
658
+ setMask(x, y)
659
+ }
660
+ }
661
+ }
662
+
663
+ // Convert string to bit stream. 8-bit data to QR-coded 8-bit data (numeric, alphanum, or kanji
664
+ // not supported).
665
+ // 将字符串转换为位流。8位数据转换为QR编码的8位数据(不支持数字、字母或汉字)。
666
+ v = str.length
667
+
668
+ // String to array.
669
+ for (i = 0; i < v; i++) {
670
+ // #ifdef APP-ANDROID
671
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
672
+ // @ts-ignore
673
+ eccBuffer[i.toInt()] = str.charCodeAt(i)!
674
+ // #endif
675
+ // #ifndef APP-ANDROID
676
+ eccBuffer[i] = str.charCodeAt(i)!
677
+ // #endif
678
+ }
679
+
680
+ //++++++++++++++++++++==============
681
+ stringBuffer.set(eccBuffer.subarray(0, v))
682
+
683
+ // Calculate max string length.
684
+ x = dataBlock * (neccBlock1 + neccBlock2) + neccBlock2
685
+
686
+ if (v >= x - 2) {
687
+ v = x - 2
688
+
689
+ if (version > 9) v--
690
+ }
691
+
692
+ // Shift and re-pack to insert length prefix.
693
+ // 移位并重新打包以插入长度前缀。
694
+ i = v
695
+
696
+ if (version > 9) {
697
+ stringBuffer[i + 2] = 0
698
+ stringBuffer[i + 3] = 0
699
+
700
+ while (i-- > 0) {
701
+ t = stringBuffer[i]
702
+
703
+ stringBuffer[i + 3] |= 255 & (t << 4)
704
+ stringBuffer[i + 2] = t >> 4
705
+ }
706
+
707
+ stringBuffer[2] |= 255 & (v << 4)
708
+ stringBuffer[1] = v >> 4
709
+ stringBuffer[0] = 0x40 | (v >> 12)
710
+ } else {
711
+ stringBuffer[i + 1] = 0
712
+ stringBuffer[i + 2] = 0
713
+
714
+ while (i-- > 0) {
715
+ t = stringBuffer[i]
716
+
717
+ stringBuffer[i + 2] |= 255 & (t << 4)
718
+ stringBuffer[i + 1] = t >> 4
719
+ }
720
+
721
+ stringBuffer[1] |= 255 & (v << 4)
722
+ stringBuffer[0] = 0x40 | (v >> 4)
723
+ }
724
+
725
+ // Fill to end with pad pattern.
726
+ // 用填充模式填充到结束。
727
+ i = v + 3 - (version < 10 ? 1 : 0)
728
+
729
+ while (i < x) {
730
+ stringBuffer[i++] = 0xec
731
+ stringBuffer[i++] = 0x11
732
+ }
733
+
734
+ // Calculate generator polynomial.
735
+ // 计算生成多项式。
736
+ polynomial = new Uint8Array(eccBlock + 1)
737
+ polynomial[0] = 1
738
+
739
+ for (i = 0; i < eccBlock; i++) {
740
+ polynomial[i + 1] = 1
741
+
742
+ for (j = i; j > 0; j--) {
743
+ polynomial[j] = polynomial[j] > 0 ? polynomial[j - 1] ^ GALOIS_EXPONENT[modN(GALOIS_LOG[polynomial[j]] + i)] : polynomial[j - 1]
744
+ }
745
+
746
+ polynomial[0] = GALOIS_EXPONENT[modN(GALOIS_LOG[polynomial[0]] + i)]
747
+ }
748
+
749
+ // Use logs for generator polynomial to save calculation step.
750
+ // 使用对数计算生成多项式以节省计算步骤。
751
+ for (i = 0; i < eccBlock; i++) {
752
+ polynomial[i] = GALOIS_LOG[polynomial[i]]
753
+ }
754
+
755
+ // Append ECC to data buffer.
756
+ // 将ECC附加到数据缓冲区。
757
+ k = x
758
+ y = 0
759
+
760
+ for (i = 0; i < neccBlock1; i++) {
761
+ appendData(y, dataBlock, k, eccBlock)
762
+
763
+ y += dataBlock
764
+ k += eccBlock
765
+ }
766
+
767
+ for (i = 0; i < neccBlock2; i++) {
768
+ appendData(y, dataBlock + 1, k, eccBlock)
769
+
770
+ y += dataBlock + 1
771
+ k += eccBlock
772
+ }
773
+
774
+ // Interleave blocks.
775
+ y = 0
776
+
777
+ for (i = 0; i < dataBlock; i++) {
778
+ for (j = 0; j < neccBlock1; j++) {
779
+ eccBuffer[y++] = stringBuffer[i + j * dataBlock]
780
+ }
781
+
782
+ for (j = 0; j < neccBlock2; j++) {
783
+ eccBuffer[y++] = stringBuffer[neccBlock1 * dataBlock + i + j * (dataBlock + 1)]
784
+ }
785
+ }
786
+
787
+ for (j = 0; j < neccBlock2; j++) {
788
+ eccBuffer[y++] = stringBuffer[neccBlock1 * dataBlock + i + j * (dataBlock + 1)]
789
+ }
790
+
791
+ for (i = 0; i < eccBlock; i++) {
792
+ for (j = 0; j < neccBlock1 + neccBlock2; j++) {
793
+ eccBuffer[y++] = stringBuffer[x + i + j * eccBlock]
794
+ }
795
+ }
796
+
797
+ stringBuffer.set(eccBuffer)
798
+
799
+ // Pack bits into frame avoiding masked area.
800
+ // 将位流打包到帧中,避免掩码区域。
801
+ x = width - 1
802
+ y = width - 1
803
+ k = 1
804
+ v = 1
805
+
806
+ // inteleaved data and ECC codes.
807
+ // 交错数据和ECC代码。
808
+ const m: number = (dataBlock + eccBlock) * (neccBlock1 + neccBlock2) + neccBlock2
809
+
810
+ for (i = 0; i < m; i++) {
811
+ t = stringBuffer[i]
812
+
813
+ for (j = 0; j < 8; j++) {
814
+ if ((0x80 & t) > 0) {
815
+ frameBuffer[x + width * y] = 1
816
+ }
817
+
818
+ // Find next fill position.
819
+ // 找到下一个填充位置。
820
+ do {
821
+ if (v > 0) {
822
+ x--
823
+ } else {
824
+ x++
825
+
826
+ if (k > 0) {
827
+ if (y != 0) {
828
+ y--
829
+ } else {
830
+ x -= 2
831
+ k = k == 0 ? 1 : 0
832
+
833
+ if (x == 6) {
834
+ x--
835
+ y = 9
836
+ }
837
+ }
838
+ } else {
839
+ if (y != width - 1) {
840
+ y++
841
+ } else {
842
+ x -= 2
843
+ k = k == 0 ? 1 : 0
844
+
845
+ if (x == 6) {
846
+ x--
847
+ y -= 8
848
+ }
849
+ }
850
+ }
851
+ }
852
+
853
+ v = v == 0 ? 1 : 0
854
+ } while (isMasked(x, y))
855
+ t <<= 1
856
+ }
857
+ }
858
+
859
+ // Save pre-mask copy of frame.
860
+ const frameBufferCopy = frameBuffer.slice(0)
861
+
862
+ t = 0
863
+ y = 30000
864
+
865
+ // Using `for` instead of `while` since in original Arduino code if an early mask was *good
866
+ // enough* it wouldn't try for a better one since they get more complex and take longer.
867
+ // 使用`for`而不是`while`,因为在原始Arduino代码中,如果早期掩码足够好,它不会尝试更好的掩码,因为它们变得更复杂并需要更长的时间。
868
+ for (k = 0; k < 8; k++) {
869
+ // Returns foreground-background imbalance.
870
+ // 返回前景色和背景色的不平衡。
871
+ applyMask(k)
872
+
873
+ x = checkBadness()
874
+
875
+ // Is current mask better than previous best?
876
+ // 当前掩码是否比之前的最佳掩码更好?
877
+ if (x < y) {
878
+ y = x
879
+ t = k
880
+ }
881
+
882
+ // Don't increment `i` to a void redoing mask.
883
+ // 不要增加`i`以避免重新做掩码。
884
+ if (t == 7) break
885
+
886
+ // Reset for next pass.
887
+ // 重置下一个循环。
888
+ frameBuffer.set(frameBufferCopy)
889
+ }
890
+
891
+ // Redo best mask as none were *good enough* (i.e. last wasn't `t`).
892
+ // 重做最佳掩码,因为没有一个掩码足够好(即最后一个不是`t`)。
893
+ if (t != k) {
894
+ // Reset buffer to pre-mask state before applying the best one
895
+ frameBuffer.set(frameBufferCopy)
896
+ applyMask(t)
897
+ }
898
+
899
+ // Add in final mask/ECC level bytes.
900
+ // 添加最终的掩码/ECC级别字节。
901
+ y = FINAL_FORMAT[t + ((eccLevel - 1) << 3)]
902
+
903
+ // Low byte.
904
+ for (k = 0; k < 8; k++) {
905
+ if ((y & 1) > 0) {
906
+ frameBuffer[width - 1 - k + width * 8] = 1
907
+
908
+ if (k < 6) {
909
+ frameBuffer[8 + width * k] = 1
910
+ } else {
911
+ frameBuffer[8 + width * (k + 1)] = 1
912
+ }
913
+ }
914
+ y >>= 1
915
+ }
916
+
917
+ // High byte.
918
+ for (k = 0; k < 7; k++) {
919
+ if ((y & 1) > 0) {
920
+ frameBuffer[8 + width * (width - 7 + k)] = 1
921
+
922
+ if (k > 0) {
923
+ frameBuffer[6 - k + width * 8] = 1
924
+ } else {
925
+ frameBuffer[7 + width * 8] = 1
926
+ }
927
+ }
928
+ y >>= 1
929
+ }
930
+
931
+ // Finally, return the image data.
932
+ return {
933
+ frameBuffer: frameBuffer,
934
+ width: width
935
+ } as GenerateFrameResult
936
+ }