tmui-cli 2.0.4 → 2.0.6

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 (197) hide show
  1. package/README.md +2 -2
  2. package/data/components.json +1 -1
  3. package/data/config.json +1 -1
  4. package/data/doc-index.json +1 -1
  5. package/data/examples/radio.vue +4 -0
  6. package/data/guides/cli.md +8 -4
  7. package/data/guides//346/233/264/346/226/260/346/227/245/345/277/227.md +2 -0
  8. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/01./346/217/222/344/273/266/347/233/256/345/275/225.md +0 -0
  9. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/tmOcr /347/246/273/347/272/277/346/226/207/346/241/243/350/257/206/345/210/253.md +0 -0
  10. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xActionmodalS /345/272/225/351/203/250/345/206/205/345/256/271/346/212/275/345/261/211.md +0 -0
  11. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xActionsheetS /345/272/225/351/203/250/345/212/250/344/275/234/350/217/234/345/215/225.md" +2 -0
  12. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xAddphonerepeatcalendarS /347/263/273/347/273/237/346/227/245/345/216/206.md +0 -0
  13. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xAppiconS /345/272/224/347/224/250/345/233/276/346/240/207/344/270/216/350/247/222/346/240/207.md" +14 -7
  14. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xBluetoothS /350/223/235/347/211/231.md +0 -0
  15. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xBlurU /350/203/214/346/231/257/346/257/233/347/216/273/347/222/203.md +0 -0
  16. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xCamreaU /345/216/237/347/224/237/347/233/270/346/234/272.md +0 -0
  17. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xChatmarkdownU AI/350/201/212/345/244/251Markdown.md +0 -0
  18. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xChinesetopinyinS /344/270/255/346/226/207/350/275/254/346/213/274/351/237/263.md +0 -0
  19. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xChooseFileS /346/226/207/344/273/266/351/200/211/346/213/251.md +0 -0
  20. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xChooseMediaS /345/252/222/344/275/223/351/200/211/346/213/251/345/231/250.md +0 -0
  21. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xCorrectS /346/226/207/346/241/243/346/240/241/346/255/243/344/270/216/350/257/206/345/210/253.md" +253 -3
  22. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xCryptoS /345/212/240/350/247/243/345/257/206.md +0 -0
  23. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xDesktopcardS /346/241/214/351/235/242/345/215/241/347/211/207/344/270/216/345/256/236/345/206/265.md +0 -0
  24. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xEditorU /345/257/214/346/226/207/346/234/254/347/274/226/350/276/221.md +0 -0
  25. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xFacedetectAlibabaS /351/230/277/351/207/214/344/272/221/345/256/236/344/272/272/350/256/244/350/257/201.md +0 -0
  26. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xFacerecU /347/246/273/347/272/277/344/272/272/350/204/270/350/257/206/345/210/253.md +0 -0
  27. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xFfmpegS /351/237/263/350/247/206/351/242/221/345/244/204/347/220/206.md +0 -0
  28. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xHtmlU HTML/345/256/211/345/205/250/346/270/262/346/237/223.md +0 -0
  29. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xKeyboardS /350/275/257/351/224/256/347/233/230.md +0 -0
  30. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xLoadingS /345/205/250/345/261/217/345/212/240/350/275/275.md +0 -0
  31. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xLocationS /345/256/232/344/275/215.md +0 -0
  32. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMakephoneS /346/213/250/346/211/223/347/224/265/350/257/235.md +0 -0
  33. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMediaplayS /345/252/222/344/275/223/346/222/255/346/224/276/344/270/216/345/275/225/345/210/266.md +0 -0
  34. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMimeS /346/226/207/344/273/266/347/261/273/345/236/213/345/227/205/346/216/242.md" +10 -0
  35. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMlkitScannigS /345/205/250/345/261/217/346/211/253/347/240/201.md +0 -0
  36. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMlkitScannigU /346/211/253/347/240/201/345/256/271/345/231/250.md +0 -0
  37. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMnnkitS /347/253/257/344/276/247/345/244/247/346/250/241/345/236/213.md +0 -0
  38. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xModalS /345/257/271/350/257/235/346/241/206.md +0 -0
  39. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xModel3dU.md +0 -0
  40. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMoreshareS /346/233/264/345/244/232/345/210/206/344/272/253/351/235/242/346/235/277.md +0 -0
  41. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMqttS MQTT/346/266/210/346/201/257.md +0 -0
  42. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xMusicnotifyS /351/200/232/347/237/245/346/240/217/351/237/263/344/271/220/346/222/255/346/224/276/345/231/250.md +0 -0
  43. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xNetworkstatusS /347/275/221/347/273/234/347/212/266/346/200/201.md +0 -0
  44. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xNotifyS /346/234/254/345/234/260/351/200/232/347/237/245.md +0 -0
  45. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xOcrS /347/246/273/347/272/277/346/226/207/346/241/243/350/257/206/345/210/253.md +0 -0
  46. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xOfficeU Office /346/226/207/346/241/243/347/274/226/350/276/221.md" +1996 -0
  47. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xOnnxkitS /347/246/273/347/272/277/350/257/255/351/237/263/350/257/206/345/210/253/344/270/216/345/220/210/346/210/220.md +0 -0
  48. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPdfS PDF/345/220/210/346/210/220.md" +24 -0
  49. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPdfU PDF/351/242/204/350/247/210.md" +8 -1
  50. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPermissionS /346/235/203/351/231/220.md +0 -0
  51. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPhonecontactS /351/200/232/350/256/257/345/275/225.md +0 -0
  52. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPhotokitS /345/233/276/347/211/207/346/260/264/345/215/260.md +0 -0
  53. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPiniaS.md +122 -0
  54. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPreviewMediaS /345/233/276/347/211/207/350/247/206/351/242/221/346/267/267/345/220/210/351/242/204/350/247/210.md +0 -0
  55. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xPrintS /347/263/273/347/273/237/346/211/223/345/215/260.md +0 -0
  56. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xScreenshotS /346/210/252/345/233/276/344/270/216/351/230/262/346/210/252/345/261/217.md +0 -0
  57. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xScreentgreyS /345/272/224/347/224/250/347/275/256/347/201/260.md +0 -0
  58. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSendsmsS /345/217/221/351/200/201/347/237/255/344/277/241.md +0 -0
  59. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xShareS /347/263/273/347/273/237/345/210/206/344/272/253.md +0 -0
  60. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSkiaU Skia/347/224/273/345/270/203.md +0 -0
  61. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSqliteS SQLite/346/225/260/346/215/256/345/272/223.md +0 -0
  62. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSseS SSE/346/216/250/351/200/201.md +0 -0
  63. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xStartintentS /346/211/223/345/274/200/345/215/217/350/256/256/351/223/276/346/216/245.md +0 -0
  64. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSvgU SVG/347/273/204/344/273/266.md +0 -0
  65. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xSwiperU /345/216/237/347/224/237/350/275/256/346/222/255.md +0 -0
  66. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xTexttovoiceS /346/226/207/346/234/254/350/275/254/350/257/255/351/237/263.md +0 -0
  67. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xTianditumapU /345/244/251/345/234/260/345/233/276.md +0 -0
  68. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xTipsS /346/266/210/346/201/257/346/217/220/347/244/272.md +0 -0
  69. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xToastS /350/275/273/346/217/220/347/244/272.md +0 -0
  70. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xUdpS UDP/351/200/232/344/277/241.md +0 -0
  71. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xUtilsS Base64/344/270/216/346/226/207/344/273/266/344/272/222/350/275/254.md +0 -0
  72. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xVibrateS /351/234/207/345/212/250.md +0 -0
  73. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xWebviewU /346/267/267/345/220/210WebView.md +0 -0
  74. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xWechatshareS /345/276/256/344/277/241/345/274/200/346/224/276/345/271/263/345/217/260.md +0 -0
  75. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xYoloS YOLO/347/233/256/346/240/207/346/243/200/346/265/213.md +0 -0
  76. package/data/tmui4x/10./346/217/222/344/273/266/345/272/223/xZipS ZIP/345/216/213/347/274/251/350/247/243/345/216/213.md +0 -0
  77. package/data/tmui4x/60.AI/350/207/252/345/212/250/345/214/226/01.Agent.md +42 -16
  78. package/data/tmui4x/60.AI/350/207/252/345/212/250/345/214/226/01./345/211/215/350/250/200.md +20 -0
  79. package/data/tmui4x/60.AI/350/207/252/345/212/250/345/214/226/04.SKILL.md +9 -8
  80. package/data/tmui4x-doc-index.json +40 -4
  81. package/data/uni-app-x-docs/.vuepress/utils/cssJson.json +1 -1
  82. package/data/uni-app-x-docs/.vuepress/utils/example-mapping.json +7 -0
  83. package/data/uni-app-x-docs/.vuepress/utils/utsApiJson.json +1 -1
  84. package/data/uni-app-x-docs/.vuepress/utils/utsComJson.json +1 -1
  85. package/data/uni-app-x-docs/.vuepress/utils/vueJson.json +1 -1
  86. package/data/uni-app-x-docs/_sidebar.md +6 -1
  87. package/data/uni-app-x-docs/api/get-location.md +6 -6
  88. package/data/uni-app-x-docs/api/modal.md +2 -1
  89. package/data/uni-app-x-docs/api/request.md +1 -0
  90. package/data/uni-app-x-docs/api/toast.md +2 -2
  91. package/data/uni-app-x-docs/api/window.md +2 -0
  92. package/data/uni-app-x-docs/collocation/app.md +10 -5
  93. package/data/uni-app-x-docs/collocation/manifest-android.md +15 -15
  94. package/data/uni-app-x-docs/collocation/manifest-ios.md +17 -16
  95. package/data/uni-app-x-docs/collocation/manifest-modules.md +10 -10
  96. package/data/uni-app-x-docs/component/map.md +10 -8
  97. package/data/uni-app-x-docs/component/video.md +8 -4
  98. package/data/uni-app-x-docs/css/_sidebar.md +0 -1
  99. package/data/uni-app-x-docs/css/common/function.md +8 -4
  100. package/data/uni-app-x-docs/css/common/selector.md +2 -0
  101. package/data/uni-app-x-docs/mp/README.md +0 -4
  102. package/data/uni-app-x-docs/mp/native-component-and-wxs.md +166 -0
  103. package/data/uni-app-x-docs/native/download/android.md +106 -19
  104. package/data/uni-app-x-docs/native/download/ios.md +11 -9
  105. package/data/uni-app-x-docs/page.md +2 -0
  106. package/data/uni-app-x-docs/project.md +6 -7
  107. package/data/uni-app-x-docs/release-note-alpha.md +142 -0
  108. package/data/uni-app-x-docs/release.md +263 -0
  109. package/data/uni-app-x-docs/select/native-render-and-self-render.md +386 -0
  110. package/data/uni-app-x-docs/tutorial/android-16kb.md +5 -1
  111. package/data/uni-app-x-docs/tutorial/app-env.md +1 -1
  112. package/data/uni-app-x-docs/tutorial/app-update-wgt.md +13 -0
  113. package/data/uni-app-x-docs/tutorial/store.md +0 -1
  114. package/data/uni-app-x-docs/uts/README.md +27 -25
  115. package/data/uni-app-x-docs/vue/README.md +64 -29
  116. package/data/uni-app-x-docs/vue/built-in.md +1 -1
  117. package/data/uni-app-x-docs/vue/component.md +1 -1
  118. package/data/uni-app-x-docs/vue/composition-api.md +6 -19
  119. package/data/uni-app-x-docs/vue/global-api.md +1 -1
  120. package/data/uniappx/_sidebar.md +6 -1
  121. package/data/uniappx/api/create-editor-context-async.md +3 -3
  122. package/data/uniappx/api/get-app-base-info.md +14 -14
  123. package/data/uniappx/api/get-file-system-manager.md +2 -2
  124. package/data/uniappx/api/get-location.md +6 -6
  125. package/data/uniappx/api/modal.md +2 -1
  126. package/data/uniappx/api/on-tab-bar-mid-button-tap.md +4 -4
  127. package/data/uniappx/api/request.md +1 -0
  128. package/data/uniappx/api/toast.md +4 -4
  129. package/data/uniappx/api/window.md +2 -0
  130. package/data/uniappx/collocation/app.md +10 -5
  131. package/data/uniappx/collocation/manifest-android.md +15 -15
  132. package/data/uniappx/collocation/manifest-ios.md +17 -16
  133. package/data/uniappx/collocation/manifest-modules.md +10 -10
  134. package/data/uniappx/component/checkbox.md +2 -2
  135. package/data/uniappx/component/input.md +9 -15
  136. package/data/uniappx/component/label.md +4 -3
  137. package/data/uniappx/component/map.md +19 -14
  138. package/data/uniappx/component/swiper.md +31 -67
  139. package/data/uniappx/component/switch.md +3 -9
  140. package/data/uniappx/component/textarea.md +4 -8
  141. package/data/uniappx/component/uni-ui-x/uni-badge-view.md +2 -2
  142. package/data/uniappx/component/uni-ui-x/uni-collapse.md +11 -55
  143. package/data/uniappx/component/uni-ui-x/uni-fab-button.md +1 -1
  144. package/data/uniappx/component/uni-ui-x/uni-link.md +1 -1
  145. package/data/uniappx/component/uni-ui-x/uni-number-box.md +2 -2
  146. package/data/uniappx/component/uni-ui-x/uni-rate.md +2 -2
  147. package/data/uniappx/component/uni-ui-x/uni-refresh-box.md +1 -1
  148. package/data/uniappx/component/uni-ui-x/uni-tab.md +44 -2
  149. package/data/uniappx/component/video.md +16 -13
  150. package/data/uniappx/component/web-view.md +10 -21
  151. package/data/uniappx/css/_sidebar.md +1 -2
  152. package/data/uniappx/css/common/function.md +7 -4
  153. package/data/uniappx/css/common/selector.md +14 -14
  154. package/data/uniappx/mp/README.md +0 -4
  155. package/data/uniappx/mp/native-component-and-wxs.md +151 -0
  156. package/data/uniappx/native/download/android.md +106 -19
  157. package/data/uniappx/native/download/ios.md +11 -9
  158. package/data/uniappx/page.md +2 -0
  159. package/data/uniappx/project.md +5 -6
  160. package/data/uniappx/release-note-alpha.md +142 -0
  161. package/data/uniappx/release.md +263 -0
  162. package/data/uniappx/select/native-render-and-self-render.md +382 -0
  163. package/data/uniappx/tutorial/android-16kb.md +5 -1
  164. package/data/uniappx/tutorial/app-env.md +1 -1
  165. package/data/uniappx/tutorial/app-update-wgt.md +9 -0
  166. package/data/uniappx/uts/README.md +27 -25
  167. package/data/uniappx/vue/README.md +11 -82
  168. package/data/uniappx/vue/built-in.md +2 -2
  169. package/data/uniappx/vue/component.md +1 -1
  170. package/data/uniappx/vue/composition-api.md +2 -86
  171. package/data/uniappx/vue/global-api.md +1 -1
  172. package/data/uniappx/vue/modifier.md +3 -3
  173. package/data/uniappx-doc-index.json +44 -16
  174. package/dist/main.mjs +65 -65
  175. package/package.json +4 -3
  176. package/templates/uniappx-vapor/.editorconfig +9 -0
  177. package/templates/uniappx-vapor/App.uvue +51 -0
  178. package/templates/uniappx-vapor/index.html +20 -0
  179. package/templates/uniappx-vapor/main.uts +9 -0
  180. package/templates/uniappx-vapor/manifest.json +67 -0
  181. package/templates/uniappx-vapor/pages/index/index.uvue +24 -0
  182. package/templates/uniappx-vapor/pages.json +17 -0
  183. package/templates/uniappx-vapor/platformConfig.json +6 -0
  184. package/templates/uniappx-vapor/static/logo.png +0 -0
  185. package/templates/uniappx-vapor/uni.scss +76 -0
  186. package/templates/uniappx-vdom/.editorconfig +9 -0
  187. package/templates/uniappx-vdom/App.uvue +51 -0
  188. package/templates/uniappx-vdom/index.html +20 -0
  189. package/templates/uniappx-vdom/main.uts +9 -0
  190. package/templates/uniappx-vdom/manifest.json +66 -0
  191. package/templates/uniappx-vdom/pages/index/index.uvue +24 -0
  192. package/templates/uniappx-vdom/pages.json +17 -0
  193. package/templates/uniappx-vdom/platformConfig.json +6 -0
  194. package/templates/uniappx-vdom/static/logo.png +0 -0
  195. package/templates/uniappx-vdom/uni.scss +76 -0
  196. package/data/uni-app-x-docs/css/css_diff_web.md +0 -802
  197. package/data/uniappx/css/css_diff_web.md +0 -802
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # tmui-cli
2
2
 
3
- TMUI DESIGN 终端工具:在命令行里创建或升级 uniapp CLI / HBX 项目,也可作为 IDE 的 MCP 服务。
3
+ TMUI DESIGN 终端工具:在命令行里创建或升级 uniapp CLI / HBX / uni-app x(VDOM、Vapor 蒸汽)项目,也可作为 IDE 的 MCP 服务。
4
4
 
5
5
  ## 环境
6
6
 
@@ -41,7 +41,7 @@ tmui
41
41
  }
42
42
  ```
43
43
 
44
- 提供的工具:`create_uniapp_hbx_project`、`create_uniapp_cli_project`、`query_tmui_config`、`list_components`、`get_component_doc`、`query_tmui_doc`。
44
+ 提供的工具:`create_uniapp_hbx_project`、`create_uniapp_cli_project`、`create_uniappx_vdom_project`、`create_uniappx_vapor_project`、`query_tmui_config`、`list_components`、`get_component_doc`、`query_tmui_doc`。
45
45
 
46
46
  ## MCP · tmui4x 2.0(蒸汽版文档)
47
47
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "updatedAt": "2026-09-09T09:08:52.413Z",
2
+ "updatedAt": "2026-09-20T01:56:08.175Z",
3
3
  "source": "/Volumes/app/myProjects/HBuilderProjects/tmui3.2\\src\\uni_modules\\tm-ui\\components",
4
4
  "count": 63,
5
5
  "components": [
package/data/config.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "updatedAt": "2026-09-09T09:08:52.420Z",
2
+ "updatedAt": "2026-09-20T01:56:08.182Z",
3
3
  "source": "/Volumes/app/myProjects/HBuilderProjects/tmui3.2\\src\\uni_modules\\tm-ui\\libs\\config.ts",
4
4
  "count": 29,
5
5
  "config": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "updatedAt": "2026-09-09T09:08:52.426Z",
2
+ "updatedAt": "2026-09-20T01:56:08.190Z",
3
3
  "count": 11,
4
4
  "guides": [
5
5
  {
@@ -44,6 +44,7 @@
44
44
  </template>
45
45
 
46
46
  <script lang="ts" setup>
47
+ import { onLoad } from '@dcloudio/uni-app'
47
48
  import { ref } from 'vue'
48
49
 
49
50
  const radioValue = ref("")
@@ -56,6 +57,9 @@ const listview = ref<Array<Record<string, any>>>([
56
57
  const onchange = (val: any) => {
57
58
  // console.log(val,'**')
58
59
  }
60
+ onLoad(()=>{
61
+ radioValue.value = "香蕉"
62
+ })
59
63
  </script>
60
64
 
61
65
  <style></style>
@@ -42,7 +42,7 @@ npx -y tmui-cli
42
42
 
43
43
  | 菜单 | 说明 |
44
44
  | --- | --- |
45
- | 创建项目 | CLI / HBX 模板 + TMUI |
45
+ | 创建项目 | CLI / HBX / uniappx 模板 |
46
46
  | 升级项目 | 升级 TMUI 或 UniSdk |
47
47
  | 访问官网主页 | 用系统默认浏览器打开 https://tmui.design |
48
48
  | 退出 | 结束进程 |
@@ -51,10 +51,12 @@ npx -y tmui-cli
51
51
 
52
52
  ### 创建项目
53
53
 
54
- 依次选择:项目类型(CLI / HBX)→ 目录 → 名称 TMUI 版本 →(仅 CLI)UniSdk 通道与版本 → npm 或 pnpm。
54
+ 依次选择:项目类型(CLI / HBX / uniappx-vdom / uniappx-vapor(蒸汽))→ 目录 → 名称 →(仅 CLI / HBX)TMUI 版本 →(仅 CLI)UniSdk 通道与版本 → npm 或 pnpm。
55
55
 
56
56
  - CLI:推荐,可用 VS Code / Cursor 等命令行编译
57
- - HBX:仅 HBuilderX
57
+ - HBX:仅 HBuilderX(vue 项目 + TMUI)
58
+ - uniappx-vdom:uni-app x VDOM 空项目,内置模板,创建时写入项目名和新 appid
59
+ - uniappx-vapor(蒸汽):uni-app x Vapor 空项目,内置模板,创建时写入项目名和新 appid
58
60
  - 依赖安装固定走阿里云源 `https://registry.npmmirror.com`
59
61
 
60
62
  ### 升级项目
@@ -102,9 +104,11 @@ Cursor 写在项目级 `.cursor/mcp.json`,VS Code / Copilot 写在用户或工
102
104
  | --- | --- |
103
105
  | `create_uniapp_hbx_project` | 创建 uniapp HBuilderX 项目(含 TMUI) |
104
106
  | `create_uniapp_cli_project` | 创建 uniapp CLI 项目(自动安装依赖,含 TMUI) |
107
+ | `create_uniappx_vdom_project` | 创建 uniappx-vdom 项目(内置模板) |
108
+ | `create_uniappx_vapor_project` | 创建 uniappx-vapor(蒸汽)项目(内置模板) |
105
109
  | `query_tmui_config` | 查询组件库全局配置(mode / unit / radius / color 等) |
106
110
  | `list_components` | 列出全部组件,按分类分组 |
107
111
  | `get_component_doc` | 获取单个组件文档与示例(如 `tm-button`) |
108
112
  | `query_tmui_doc` | 查询引导/配置文档(常见问题、快速上手、安装等) |
109
113
 
110
- 创建类工具与交互菜单共用同一套创建逻辑。CLI 项目未指定版本时,默认取 CDN 最新 TMUI、正式包最新 UniSdk,安装器默认 npm。
114
+ 创建类工具与交互菜单共用同一套创建逻辑。CLI 项目未指定版本时,默认取 CDN 最新 TMUI、正式包最新 UniSdk,安装器默认 npm。uniappx-vdom / uniappx-vapor(蒸汽)使用 CLI 内置模板,无需 TMUI 或 UniSdk 版本,会把项目名写入 `manifest.json` 并生成新的 `appid`。
@@ -14,6 +14,8 @@ import headertips from '../components/headertips.vue'
14
14
 
15
15
  ### :couplekiss: 更新日志
16
16
 
17
+ ## 3.2.22(2026-09-14)
18
+ * 修复一些问题
17
19
  ## 3.2.21(2026-09-07)
18
20
  * 优化一些组件及配置
19
21
  ## 3.2.20(2026-08-12)
@@ -88,6 +88,8 @@ hideActionSheet()
88
88
 
89
89
  ## 更新日志
90
90
 
91
+ ### 1.0.2(2026-09-08)
92
+ * 蒸汽 Android:关闭动画 `alpha` 不再把 `toFloat()` 赋给中间变量,避免编成 Kotlin `Number` 传给只要 `Float` 的 API。
91
93
  ### 1.0.1(2026-08-14)
92
94
  * App 三端复制独立字体 `x-actionsheet-remixicon.ttf`(族名同步改名),避免和其它插件的 `remixicon.ttf` 资源冲突。
93
95
  * Web 图标字体族名为 `x-actionsheet-remixicon`,文件使用全局 `/static/tmui4xLibs/static/remixicon.ttf`。
@@ -2,7 +2,7 @@
2
2
 
3
3
  类似淘宝:运行时切换**预置桌面图标**,并设置桌面**角标数字 / 小红点**。标准 `-s` API 插件,页面 `import` 后直接调用。
4
4
 
5
- **远程图片不能作为桌面图标。** iOS、Android、HarmonyOS 都要求图标打进安装包(或走应用市场上架的图标管理)。本插件内置 `festival` / `sale` / `newyear` 三套图;要换自己的图,替换插件资源并保持同名即可。
5
+ **远程图片不能作为桌面图标。** iOS、Android、HarmonyOS 都要求图标打进安装包(或走应用市场上架的图标管理)。本插件内置 `default` / `sanbu` / `zuoyiqi` / `shuijiao` / `wangwang` / `black` 六套图;要换自己的图,替换插件资源并保持同名即可。
6
6
 
7
7
  切换图标、角标都要**自定义基座 / 云打包**后才生效。部分桌面不会立刻刷新,回到桌面等几秒,或重新打开桌面。
8
8
 
@@ -66,7 +66,7 @@ import {
66
66
  const caps = xGetAppIconCapabilities()
67
67
 
68
68
  xSetAppIcon({
69
- name: "festival",
69
+ name: "sanbu",
70
70
  success: (res) => {
71
71
  console.log(res.name)
72
72
  }
@@ -84,10 +84,12 @@ xSetAppBadge({
84
84
 
85
85
  | name | 说明 |
86
86
  | --- | --- |
87
- | default | 恢复应用原图标 |
88
- | festival | 节日红金(双 11 风格) |
89
- | sale | 促销橙 |
90
- | newyear | 春节红金 |
87
+ | default | 默认白底 |
88
+ | sanbu | 散步 |
89
+ | zuoyiqi | 坐一起 |
90
+ | shuijiao | 睡觉 |
91
+ | wangwang | 汪汪 |
92
+ | black | 黑底 |
91
93
 
92
94
  Android 图标在 `utssdk/app-android/res/mipmap-*`。iOS 图标在 `utssdk/app-ios/Resources/x_appicon_{name}@2x.png` 与 `@3x.png`。
93
95
 
@@ -131,7 +133,7 @@ Android 图标在 `utssdk/app-android/res/mipmap-*`。iOS 图标在 `utssdk/app-
131
133
  </activity>
132
134
  ```
133
135
 
134
- 改完后卸载重装。插件 alias:`XAppIconDefault` / `XAppIconFestival` / `XAppIconSale` / `XAppIconNewyear`。
136
+ 改完后卸载重装。插件 alias:`XAppIconDefault` / `XAppIconSanbu` / `XAppIconZuoyiqi` / `XAppIconShuijiao` / `XAppIconWangwang` / `XAppIconBlack`。
135
137
 
136
138
  ### iOS 说明
137
139
 
@@ -147,6 +149,11 @@ Android 图标在 `utssdk/app-android/res/mipmap-*`。iOS 图标在 `utssdk/app-
147
149
 
148
150
  ## 更新日志
149
151
 
152
+ ### 1.0.7(2026-09-09)
153
+
154
+ - 预置图标改为 6 套:`default` / `sanbu` / `zuoyiqi` / `shuijiao` / `wangwang` / `black`
155
+ - 按各端规范生成 Android mipmap、iOS @2x/@3x、Harmony media、Web 180px 资源
156
+
150
157
  ### 1.0.6(2026-08-17)
151
158
 
152
159
  - 去掉 iOS `showAlert` 参数和演示页「用系统弹层切换」入口,切图标只走静默
@@ -17,6 +17,7 @@ openCorrect({
17
17
  title: "文档校正",
18
18
  autoConfirm: false,
19
19
  stretch: true,
20
+ enhanceMode: "document",
20
21
  ocr: true,
21
22
  success: (res) => {
22
23
  console.log(res.tempFilePaths)
@@ -28,7 +29,18 @@ openCorrect({
28
29
 
29
30
  `autoConfirm: true` 时不出现拉角和二次确认,适合连拍存档。找不到纸面四角时仍保存原图。`stretch: false` 时不做透视拉正:自动模式直接存原图;手动模式只显示预览图,打勾保存,不出现拉角和识别叠字。手动确认预览时右侧「完成」会隐藏,回到拍照界面再显示。
30
31
 
31
- 拍照先冻结当前预览,界面不再跟着实时流走。三端接着用高清拍照口出存档图再拉正;找角和 OCR 按长边缩小。拍照失败才回退预览帧。
32
+ 拍照落盘前先按纸面情况智能增强,且只在**拉正之后**做(此时纸已占满画面,统计口径才成立)。增强分两种模式,取景界面上有菜单可实时切换,默认文档增强:
33
+
34
+ - `enhanceMode: "document"`(文档增强,默认):色调照搬在 Photoshop 里标定好的四个调整值 —— 亮度/对比度(PS「非旧版」)−10 / +71 → 黑白(六色权重 红19 黄50 绿21 青60 蓝27 洋红56)→ 色阶(黑场 10、中灰 1.00、白场 188,即把 [10,188] 拉满到 [0,255])→ 纸面亮度归一 → 轻锐化。PS 的亮度曲线端点固定(0→0、1→1),对比度是绕 0.5 的二次 S 曲线,所以提对比不裁高光也不切死黑;黑白用 max/mid/min 分解按色相加权,纯红/纯黄等六个原色正好等于对应权重 ×255。色调链是固定 LUT,同一张输入在任何设备上都出同一结果。链前还有两步按拍摄条件做的自适应准备(白平衡去黄偏、分块匀光去阴影和台灯亮斑,匀光带内容保护、只修纸面背景不缩放照片与墨迹),链后按实测纸面亮度做一次归一(目标 248,增益限制 0.90~1.35,纸面本身在 248 附近的图增益≈1、与 PS 逐像素一致)。另外**白场会按纸面亮度自适应**:纸面在色阶输入端的落点超过 188 时,白场抬到纸面之上留 12 级高光余量——拍得很白的纸因此不会整片裁成死白,纸纹和反光保留(合成亮纸图实测纸纹幅度从 2~5 级恢复到 23~33 级);纸面比白场暗时白场仍是 188,行为与 PS 一致。整条自适应准备(白平衡、匀光、自适应白场、纸面归一)可以用 `-DXCORRECT_DOC_KEEP_AUTO_PREP=0` 关掉,关掉后是严格 PS 复刻。锐化排在最后一步,避免字边过冲被纸面提亮顶到 255 裁平。用户给的「纯文本」与「风景票证」两张参考图都做了分位数对拍,误差在几级以内(详见 changelog)。
35
+ - `enhanceMode: "scan"`(原图扫描):保留彩色,只按中位亮度温和提亮 + 轻锐化,不动白平衡和色调链,也不黑白化。适合本来就有颜色、需要留档的图。
36
+
37
+ 锐化排在最后一步:它按像素亮度自适应(字边压暗限幅、亮部软上限),在最终亮度域上才能如实作用,也不会像链内锐化那样造出被纸面提亮顶裁的高光(合成图实测 71.7% 纸面像素被打满 255)。`stretch: false` 不拉正时画面仍含桌面背景,统计口径不成立,退回通用增强安全提亮。不另加图像库,走插件自带 C++ 核。相册图不改。
38
+
39
+ 取景按 4:3 居中,上下黑边放导航、分辨率档和快门,不再铺满全屏。顶栏下列出最多 5 档拍照分辨率,默认超高清(最高一档)。三端档位的来源不同:Android / 鸿蒙直接枚举硬件支持的全部 JPEG 输出尺寸;iOS 因为「单个 format 的可选拍照尺寸通常只有 1 项」且切 format 容易闪退,改为只读枚举出传感器最大 4:3 尺寸,档位表示**输出分辨率**——始终按最大尺寸拍摄,落盘前按所选档位长边降采样,所以三端都能给出 5 档,切档也不会重配相机会话。
40
+
41
+ 界面从上到下是:顶栏 → 分辨率档 → 相机预览 → 画质模式菜单 → 缩略图条 → 底部工具栏。画质模式菜单是居中的两个胶囊按钮「原图扫描 / 文档增强」,只在取景态显示(确认态和结果态隐藏,因为那时改动不会影响已生成的预览)。缩略图条紧贴底部工具栏。实时框只描边不填充,避免绿色盖住纸面内容。
42
+
43
+ 扫描时实时框只跑 256 热力图模型,不用传统 C 算法兜底——传统算法会在纯色、手指蒙镜头、阴影边缘上凭空拼出矩形导致实时框乱跳,而模型对这些场景的响应实测 ≤0.012,真实纸面在 0.6 以上。模型检不出就不画框,拍照后的编辑确认框仍走「模型 + 传统 + 证据门禁」,兜底能力保留在静图路径上。三端都在 native 侧一趟完成「转正 + 重采样到 256×256」,不整帧转位图:Android 直接取相机分析帧的原始 RGBA 缓冲按 rotationDegrees 转正;鸿蒙实时帧是 NV21 原始像素(分析流 profile 是 `CAMERA_FORMAT_YUV_420_SP`),走 `detect_from_nv21_live` 在 C++ 里直接做 NV21→RGB + 按传感器朝向转正 + 重采样,省掉 ArkTS 侧四次图像 API 往返和中间 RGBA 缓冲的跨语言拷贝(鸿蒙前摄仍需镜像,保留原 RGBA 路径)。拍照确认框与实时框一致;找不到实时框时再对成片找角。拍照先冻结当前预览,界面不再跟着实时流走。三端接着用所选分辨率拍照口出存档图再拉正;找角和 OCR 按长边缩小。拍照失败才回退预览帧。
32
44
 
33
45
  `ocr: true` 时每张落盘后用内置 PP-OCRv5 mobile 识别,结果在 `tempFiles.text` / `texts` / `lines`。拼文本 PDF 用无坐标的 `texts`,按页换行连接、页间空一行即可。iOS 取 `texts` 不要用模板字符串,否则会变成 `Optional(文字)`。手动确认(`autoConfirm: false`)时识别完会停在拉正图上,文字盖在对应行上,长按该行可复制。`autoConfirm: true` 仍是连拍,不打断预览。模型没就绪或识别被阈值丢掉时会提示原因。改完请重新编译安装。也可单独调用:
34
46
 
@@ -59,17 +71,255 @@ ocrImage({
59
71
  | torch | 初始闪光灯 | false |
60
72
  | autoConfirm | 自动校正并连拍 | false |
61
73
  | stretch | 是否透视拉正(矫正拉伸) | true |
74
+ | enhanceMode | 画质模式:`document` 文档增强(灰阶黑白)/ `scan` 原图扫描(保留彩色,轻提亮轻锐化)。弹层内取景界面也有菜单可实时切换 | `document` |
62
75
  | maxCount | 最多张数 | 20 |
63
76
  | outputType | `jpg` / `png` | `jpg` |
64
77
  | quality | jpg 质量 | 92 |
65
78
  | ocr | 校正后识别文字 | false |
66
79
 
67
- `XCorrectFile`:`path`、`width`、`height`、`source`(`camera` / `album`)、`corrected`、`text`(全文)、`texts`(无坐标行数组)、`lines`(带框)。`ocrImage` 的 `text` 本身就是行数组。
80
+ `XCorrectFile`:`path`、`width`、`height`、`source`(`camera` / `album`)、`corrected`、`text`(全文)、`texts`(无坐标行数组)、`lines`(带框)。`ocrImage` 的 `text` 本身就是行数组。每行带 `box`(四点框)、`kind`(`text` / `table_cell`)、`fontPx`(**建议字号,图片像素**:按框内墨迹量出来的,叠字时直接用它就和图上的字一样大;检测框比字高大约 1.6 倍,拿框高算会大 20%~40%。墨迹的高度与宽度两条路都走,分数栈、上下标、括号、图形把「墨迹带」撑高时用宽度那一路,再用整页正文字号的量级兜底,所以同一页里大标题与正文的相对大小能对上),以及 **`inkTop` / `inkH` / `baseline`**(墨迹带顶、墨迹带高、基线,都是图片像素):叠字要贴着墨迹画,检测框上下留白不匀(多出的留白偏下),按框居中会让整行往下掉。画布类渲染直接用 `baseline`;只能按容器摆的(ArkUI `Text`)用 `inkTop + inkH/2` 当中心。没量出来时这三个都是 0,此时按框兜底。
68
81
 
69
- OCR 只处理印刷/手写文本行。竖排会先转成横条再认。表格结构、数学公式要另加版面和专用模型,不能靠 v5 rec 硬认。
82
+ OCR 只处理印刷/手写文本行。竖排会先转成横条再认。表格用几何方法还行列顺序(`table_cell`),取舍和局限见 [models/README.md](models/README.md)。
70
83
 
71
84
  ## 更新日志
72
85
 
86
+ ### 0.1.63(2026-09-12)
87
+ - **去掉实时取景里「纸张没完全进画面:把镜头拉远一点」的提示**,用户反馈它出现得太频繁、提示条正好压在底部按钮上,比它解决的事更扰人。三端都删:安卓取景框底部那颗药丸(`liveHintView`)、iOS 底部那行 `liveHintLabel`、鸿蒙弹的那句 toast。
88
+ - 只动前台三端:C++ 的判定与 JSON 里的 `hint` 字段原样保留(省掉三端原生库重编),三端结果类里的 `hint` 字段与解析一并删掉。其余提示(「已复制」「未识别到区域,请重新拍摄」「未识别到文字」)不变。
89
+
90
+ ### 0.1.62(2026-09-12)
91
+ - **公式识别整条链路下线**(用户决定:识别效果不稳定,收益不抵体积与故障面)。删掉的东西:
92
+ - 原生:`common/XCorrectFormula.cpp`(PP-FormulaNet_plus-S 装载/预处理/解码 + 整行判定 + 行内公式 + 分数栈并块)、`common/XCorrectLatex.cpp`(LaTeX → 可读近似文本)、`OcrBoxLine` 里的 `absorbed` / `char_x`、CTC 解码回传的时间步、以及 `ocr_from_rgba` 里三次公式调用。三端 CMake / 构建脚本里的源文件与模型拷贝一并去掉。
93
+ - 三端桥接:`nativeInitFormula` / `nativeSetFormulaEnabled` / `nativeFormula` / `nativeFormulaError` 四个导出(napi / JNI / ObjC)、`XCorrectConfig.math` 开关(含 interface.uts、三端 index.uts、演示页开关)、鸿蒙那套 294MB rawfile 的流式拷贝与字节校验代码。
94
+ - 资源:三端打包目录里的 `formula_ppformulanet_plus_s.onnx`(308MB)与 `formula_vocab.txt`、`models/prepare_formula.sh`、`models/verify_formula.py`、Paddle 推理件与转换 venv(约 1GB),以及 `models/README.md` 里的公式章节。
95
+ - 结果结构:保留 `kind`(仍有 `text` / `table_cell`),删掉恒为空串的 `latex` —— `XCorrectOcrLine`(interface.uts + 三端解析 + `XCorrectOcr.cpp` 的 JSON 输出)、`XPdfTextLine` 与演示页的透传一并去掉,三端产物重新编译。
96
+ - 体积变化:鸿蒙运行包(HAP)**393MB → 83.8MB**;iOS framework 581KB → 398KB、har 29.6MB → 29.6MB(OCR 模型没动)。
97
+ - 顺带说明下线原因:最后一次真机日志 `formula model missing: copy mismatch` 是「拷完抽头尾比对」检查报出来的 —— 鸿蒙侧从 rawfile 流式拷到缓存的那份模型**内容确实是坏的**(不是大小不对,是 offset 解释不一致),ORT 装载必然失败,之前那串「装载失败 + 闪退」都源于这里。做模型校验时的经验留在 `XCorrectOcr.cpp` 的墨迹测量里(`inkTop` / `inkH` / `baseline` 继续给叠字用)。
98
+ - 主机测试架跟着瘦身:只留整页 OCR 回归(`MODE` 开关与公式判定表 `pred_test` 一并删掉),`native-src/host/README.md` 重写了用法。
99
+
100
+ ### 0.1.61(2026-09-11)
101
+ - **叠字(预览 + PDF)改用「墨迹」落笔**。OCR 一直算着墨迹带与基线(`inkTop` / `inkH` / `baseline`),但三端预览叠字都没用过:安卓按「框顶 + ascent」、鸿蒙按「框内居中」、iOS 从框顶再退一个 ascent —— 检测框上下留白不匀(多出的留白偏下,框常把上下标、下一行的头框进来),按框摆就会整体往下掉。现在三端预览的 OCR 行都接上这三个量:
102
+ - 安卓:`drawText` 的 baseline 用 OCR 量出来的那条(没量出来才退回框顶算法);
103
+ - iOS:从基线往上退 `ascender`(`draw(at:)` 的点是文字框左上角)—— 顺带修掉原来从框顶退 ascent、把字整体抬高的写法;
104
+ - 鸿蒙:ArkUI 的 `Text` 不能直接给基线,改成「容器中心 = 墨迹带中心」(容器高度仍是检测框高,免得 ArkUI 的行高把字裁掉),检测框本身留在原处不动。
105
+ - 行框被缩放时(`scaleOcrLines`)这三个量跟着一起缩;不缩基线会带着字整体偏下。
106
+ - **公式模型装载失败只试一次**。模型 194~294MB,之前失败不记录,三端桥接每张图都会再试一遍 —— 真机上的「闪退」就是这么来的(一串几百 MB 的分配 + ORT 建图)。现在 `init_formula_models` 记住失败与原因,鸿蒙桥接侧也加了 `formulaAttempted`,失败后直接返回同一句日志,不再碰模型。
107
+ - **鸿蒙侧补上失败原因**:新增 `nativeFormulaError` 导出(直接返回 C++ 记下的那句话)与 hilog 输出(`formula init failed: …`)。`nativeInitFormula` 返回 false 时 ArkTS 先问它,再退回原来的「喂 8×8 空图问 errMsg」兜底 —— 那条老路任何一步抛异常都会把原因吃掉,日志里只剩「未就绪」,排查时分不清是文件坏了、版本不匹配还是没内存。
108
+ - **正文字号不再被宽度路压小一圈**。`suggest_font_px` 里「宽度路比高度路小 15% 就切宽度路」的门槛太敏感:宽度路 = 墨迹宽 ÷ 文本宽,OCR 多认几个字就会偏小一两成,于是正常正文行被切到宽度路、画出来比图上的字小两成(真机反馈的「字小了 1/4」)。现在:
109
+ - 高度路只有被**明显**撑高(墨迹带 ≥ 1.35 倍)才切宽度路 —— 撑高的真实量级是 1.6~2.3 倍(分数栈、括号、图形),两边分得开;
110
+ - `page_body_px` 收样本时同样用 1.35 倍这条线,并且取**高度路**当中位数(宽度路会被多认的字带小);
111
+ - 大字夹逼(> 1.15 倍正文)除了「两条路对不上」,再加一条「高度路本身超过正文 1.8 倍」—— 并块(分数栈 + 下一行)两条路会一起偏大、互相印证,只有这条量级线拦得住;真大标题 1.5~1.7 倍,不受影响。
112
+ - 同一张数学卷(1212×1800)实测:正文 18.9~21.6 → 21.6~26.1(该页正文实测字高约 21px,换算字号约 23.9),标题仍是 35.2、选项行仍是 25.4~28.8,并块行从 58.9 回落到 28.8。
113
+
114
+ ### 0.1.60(2026-09-11)
115
+ - **修鸿蒙真机上「公式模型未启用:formula model missing」**。模型其实好好地在包里 —— 实测打出来的 `entry-default-signed.hap` 里有 `resources/rawfile/x-correct-s/formula_ppformulanet_plus_s.onnx`(308MB,未压缩存放)。问题在读取方式:小模型(corner / OCR / 词典)走的是 `resourceManager.getRawFileContentSync`,而 294MB 的公式模型为了不占 300MB 堆改成了「流式拷贝」,却用 `fs.openSync('x-correct-s/xxx')` 当普通文件路径打开 —— rawfile 在 HAP 包里,不是沙箱里的文件,真机上必然 ENOENT,于是 `releaseLargeRawFile` 直接返回空串、日志只报 missing。
116
+ - 现在改走资源管理器:`getRawFdSync` 拿到这段 rawfile 的 `fd` + 在包里的起始偏移 + 长度,按 4MB 分块 `readSync`(第一块用 `offset` 定位,之后靠文件指针自己前进)写进 `cacheDir/x-correct-s/formula`,结束按官方做法 `closeRawFdSync` 关闭 fd,再交给 C++ 侧当真实路径装载。与官方 JsEtsAPI 参考里的 `readSync(data.fd, buf, { offset: data.offset, length })` + `closeRawFdSync` 用法一致。
117
+ - 顺手把失败原因写清楚:`formulaReleaseDetail` 记录具体原因,日志里现在是 `formula model missing: rawfile not packed: x-correct-s/…` / `rawfile too small: … 0 < 150000000` / `copy truncated (n/m)` / `cache dir unavailable (…)`,下次一眼能分出「没打进包」「打不开」「拷坏了」。
118
+ - 另外两端本来就没这个问题:Android 用 `assets.open(...).copyTo(...)` 流式拷(大文件 OK),iOS 用 Bundle 资源路径 + `FileManager.copyItem`(真实文件路径 OK)。这次只改鸿蒙 `.ets`,`x-correct-native.har` 与 C++ 都没动,重新编译一次应用即可生效。
119
+
120
+ ### 0.1.59(2026-09-11)
121
+ - **修「叠字与纯文本出图里部分行比图上的字大一倍、画出来还被裁」**。0.1.58 把字号改成按墨迹量之后正文对上了,但**墨迹带比字高**的行会算大一倍:二维分式栈、上下标、括号、整块图形被同一个检测框框进来时,「墨迹主体高度」量到的是整块的高度(试卷上一行分数栈的墨迹带到正文字高的 2.3 倍)。`suggest_font_px` 现在同时走两条路,再用整页正文字号的量级兜底:
122
+ - **高度路**(原有):墨迹主体高度 ÷ 字面比例(CJK 0.88 / 拉丁 0.96 / 大写数字 0.72)。
123
+ - **宽度路**(新增):墨迹宽度 ÷ 识别文本折算宽。新增 `text_advance_em` 把文本折成「几个 em 宽」(CJK 与全角标点 1.0、数字与拉丁字母约 0.5、英文窄标点 0.28),分数栈、上下标、括号、图形都影响不到它。**比高度路小 15% 以上的行改用宽度路**,再乘 0.85 —— 这类行的识别文本常常只是二维栈的一部分,少认几个字就把宽度路算大,两页试卷实测中位偏大 20%;另留「不低于整页正文 80%」的下限,免得正常行被相邻墨迹带高之后被压得太小。
124
+ - **整页正文量级**(新增 `page_body_px`):取「字数 ≥5、墨迹没有比认出来的字宽出一截」的文字行,按两条路里较小的那个取中位数。**比它大 15% 以上、而两条路又对不上的行拉回 1.15 倍以内** —— 图形、被切碎的多行框、只认出几个字的长框都属于这一类;大标题因为两条路互相印证(实测相差 6%~10%)照原样保留。
125
+ - 两页真实试卷(1206×1790 与 1210×1838,正文约 21 px)实测:
126
+ | 行 | 0.1.58 | 0.1.59 | 说明 |
127
+ | --- | --- | --- | --- |
128
+ | 大标题「重庆市2025年初中学业水平暨高中招生考试」 | 34.1 | 34.1 | 两条路互证,不动 |
129
+ | 「数学试题」 | 35.2 | 35.2 | 同上 |
130
+ | 「参考公式:抛物线…」(含分式栈) | 35.2 | 24.0 | 原来大一倍 |
131
+ | 「4.如图,点A,B,C在…∠AOB=100°」 | 32.3 | 22.3 | 同上 |
132
+ | 「9.如图,正方形ABCD…」 | 28.4 | 19.1 | |
133
+ | 「点H,连接GH,则△DGH的面积…」 | 30.7 | 20.3 | |
134
+ | 「10.已知整式M:a₀+a₁x+…,其中…」 | 34.4 | 27.2 | 被切成两段的大框 |
135
+ | 「[2x−2<x①」(不等式碎片) | 44.4 | 25.6 | |
136
+ | 「14.若实数x,y同时满足…」 | 44.3 | 27.2 | |
137
+ | 图形里认出来的「0 GB」 | 104.2 | 18.9 | 原来是 5 倍 |
138
+ | 图形里认出来的「GB」 | 59.4 | 18.9 | |
139
+ | 图案选项里的「M0」「βn」「&」 | 68.8 / 90.3 / 62.5 | 27.2 | 拉回正文量级 |
140
+ | 正文「17.求不等式组:」「第一步:构造角平分线.」 | 21.6 | 18.9 / 21.6 | 基本不动 |
141
+ - 字号不再超框之后,预览叠字与 PDF 叠字里「文字被框裁掉」的观感跟着消失(检测框本来就是字高的 1.6 倍,字号没超框就不会被裁)。三端 aar / framework / har 已按新 C++ 重新编译。
142
+
143
+ ### 0.1.58(2026-09-11)
144
+ - **字号改成按墨迹量出来的**(`fontPx`),不再拿框高乘系数。检测框上下有留白,实测框高约是字高的 **1.6 倍**(试卷正文框高 36 而字高 23,带上下标的公式行 53 vs 30),所以「框高 × 0.85」画出来比图上的字大 20%~40%,数学行最夸张。现在 `XCorrectOcr.cpp` 在出结果前量两件事:框内墨迹的紧边界、以及**主体段高度**(横向投影里墨迹总量最大的一段 —— 不能取最高的一行,分数线的横杠暗像素最多会把主体压成两行),再按字面占字号的比换算字号:CJK 0.88 em、带上升/下降部的拉丁 0.96 em、只有大写数字符号 0.72 em。实测同一页:正文 26(旧 30)、标题 34(旧 39)、公式行 35(旧 45),与图上字高一致。
145
+ - 三端预览叠字与三端 PDF 叠字都改用 `fontPx`(拿不到时才退回老办法)。**有实测字号时不再套 `minFontPt`**:大扫描件上的小字本来就小,套 10pt 会把整页文字放大一倍不止,反而和底图对不上,改成只留 3pt 的绝对下限。行框被缩放时(`scaleOcrLines`)字号跟着一起缩。
146
+ - 修 `x-pdf-s` 的 `encodeLineObj` 只序列化 `text` / `box`:`kind` / `latex` / 新增的 `fontPx` 全被丢掉,所以 PDF 侧一直拿不到公式标记和字号。
147
+ - 修**鸿蒙侧 OCR 行没解析 `kind` / `latex`**:公式行在鸿蒙上一律是 `text`,复制不到 LaTeX、也数不出「公式 N 条」。顺手补上 `fontPx`。
148
+ - 公式判定新增两道门,修「整页答案选项都被标成公式」:**选项行 / 序号行**(行首 `A.`–`D.` 加点/顿号/括号,或带圈数字 ①②③)与**可见字符 ≤ 2 的碎片**不再喂模型。实测一张数学卷 78 行里原本 44 行被判成公式(`\boxed{2}`、`\frac{\text{Aa2}}{\text{Aa}}` 这类脑补结果),现在降到 4 行,且都是真的数学碎片。
149
+ - 公式判定加**每页 2.5s 推理预算**(`kClassifyBudgetMs`):超预算就停止判定、剩下的行按普通文字处理。实测手机所用的 ORT 上单次推理 0.4~0.9s,进到整页链路里还会更慢(和 OCR 会话争内存/线程),不设上限时一张密集试卷能跑几十秒。
150
+ - **公式模型默认装 foat32 版(294MB),不再默认装 194MB 的 QDQ 版**。原因是手机上的 ORT(Android/iOS 1.28、鸿蒙 1.16.3)**不会折叠 `DequantizeLinear`**,每次推理都要把 194MB int8 权重算回 float32:整页链路实测 8.4s vs 5.3s,单次推理 0.88s vs 0.50s。省 100MB 体积要多花 1.7 倍时间,默认给快的,`./prepare_formula.sh --qdq` 可换回小体积版(脚本会打印这个取舍)。
151
+ - PDF 叠字的底图透明度支持 **0**:为 0 时不画底图,页面尺寸与文字位置仍按叠图那套走(和「纯文本出图」的区别是后者会按图片比例重排页面)。
152
+ - 演示页:底图透明度加了 **0.1** 档(默认,方便核对文字位置)和「0 不画底图」档;字号系数改成「字号微调」,默认 1.00 = 与图上的字一样高(原来是框高系数,默认 0.85)。
153
+ - **行内公式**(嵌在中文句子里的数学)接了一条独立路径 `extract_inline_formulas`:CTC 记字符时间步 → 映射回图片横向位置 → 切数学段 → 单独喂模型 → 校验通过才替换原文,行标成 `mixed`、`latex` 存这些段的 LaTeX。校验三道:不含 `\begin{}` / `\boxed` 整块结构、不是命令名当文字、**LaTeX 的字母数字要覆盖原文 60% 以上**(切片常切在词中间,模型会顺着编,实测把 `G` 读成 `.\angleADG\`)。
154
+ - 它的上限由 OCR 文本决定:试卷里的行内数学恰恰是 OCR 最容易读错的部分(`抛物线y=ax²+bx+c(a≠0)` → `物线)=ax²+bx+c(a≠ )`),碎掉之后切出来就是 `+bx+c(a≠ )` 这种片段,模型对片段只会编,于是被校验挡掉 —— 宁可不认,也不把正文换成乱码。想让行内稳定出 LaTeX,正确做法是在**图像侧检测公式区域**(公式检测模型先框出行内公式),另一套模型与流程。
155
+ - **修「模型把行内切片当二维块」的根因**:预处理原来把内容贴在 384×384 画布的左上角,下面一大片黑,模型当成多行公式块、吐 `\begin{aligned}` 模板(13 个干净行内样本 12 个中招)。改成**内容居中**后同一批样本全部读对,独立公式也更准(尾巴不再错成 `{}^--2nu\tau{{}}_{{}0W}_`,且不再带 `\begin{array}` 外壳)。这一条同时提升了整行公式与独立公式的识别质量。
156
+ - 行内公式的规模控制:一页最多 8 次推理,每行最多 2 段,候选按「数学段长度」从大到小取(预算花在最长的公式上),并跳过首尾是运算符的碎片(`+bx+c(` 这种是从表达式中间切出来的)。
157
+
158
+ ### 0.1.57(2026-09-11)
159
+ - 修「公式行复制不到 LaTeX」:OCR 结果 JSON 里 `lines[].latex` 一直写的是空串,三端长按复制拿到的还是可读近似文本。`XCorrectOcr.cpp` 现在填的是 `row.latex`。
160
+ - 公式模型换成 **QDQ 形式**(194MB)作为默认交付,不再装 294MB 的 float32 版。int8 权重之后挂一个 `DequantizeLinear`(逐通道 scale)算回 float32,ORT 装载时自己折叠——用的是标准 ONNX 算子,`DequantizeLinear` 从 opset 10 就有,鸿蒙的 ORT 1.16.3 也认。同图实测 token 输出与 float32 版**逐位一致**。
161
+ - 桌面实测:QDQ 194MB / 装载 0.23s / 单张 0.12s / 峰值 745MB;float32 294MB / 0.39s / 0.10s / 827MB。少 100MB 体积、装载更快、峰值更低,代价是单张多 20ms。
162
+ - `prepare_formula.sh` 默认装 QDQ 版,`--fp32` 可换回 float32 版(留给个别设备排查);`--int8-only` 废弃——它产出的裸 int8 张量 ORT 装载不了,而 QDQ 版同样是 194MB 且能装载。
163
+ - 三端资源下限从 200MB 降到 150MB,同时容得下两版,只用来挡「资源被截断」。
164
+ - 修 `prepare_formula.sh` 第 4 步「拷贝到三端资源目录」**一个都没拷**:模块根目录按 `models/../..` 解析到了仓库根,三个目标目录全被判为不存在,脚本却照样报成功。现在按 `models/..` 解析并统计拷贝数量,一个都没找到直接报错退出。三端资源目录里装的模型名统一成 `formula_ppformulanet_plus_s.onnx`,桥接侧不用感知版本差异。
165
+ - 新增 [models/verify_formula.py](models/verify_formula.py):按 `XCorrectFormula.cpp` 同样的预处理喂一张图,对比各版本模型的 token 是否逐位一致,并打印解出来的 LaTeX。
166
+ - 新增 [native-src/host](native-src/host/README.md):主机测试。把 `common/` 的 C++ 用**与手机同版本的 ONNX Runtime**(Android / iOS 1.28.0、鸿蒙 1.16.3)编成可执行文件,验证模型装载、C++ 预处理与 Python 参考实现是否一致、整页 OCR 链的 JSON,以及公式判定表(`MODE=pred`,秒级)。上面那个「整行英文被判成公式」的坑就是它抓出来的。
167
+ - 修 aar 打包把 `models/` 整个目录收进去:模型转换的中间件、`paddle_formula/`、Python venv 全被打进 aar,aar 从 35MB 涨到 865MB(解开 2GB)。现在先摆一个显式的暂存目录,只收模型文件,再打 aar;`models/` 里的杂物再也不会进包。
168
+ - 公式模型**默认不打进 aar**:aar 是入库的二进制文件,194MB 进 git 不合适,改走 `utssdk/app-android/assets/`(与 iOS / 鸿蒙同一条路)。真机日志若提示 `formula model missing`,用 `PACK_FORMULA=1 ./build_android.sh` 重打一次即可把模型塞进 aar。
169
+ - `prepare_formula.sh` 跑完清理 334MB 的中间件 `formula_fp32.onnx`。
170
+ - 量化脚本不再产出中间文件 `formula_ppformulanet_plus_s_int8.onnx`(QDQ 版取代了它的位置)。
171
+ - 装载失败时的提示改成「重新跑一次 prepare_formula.sh」,不再指向已废弃的 `--fp32`。
172
+ - 顺带把仓库 readme 里「数学公式要另加专用模型」这句旧结论改成现在的实际实现。
173
+ - 收紧公式判定,修「整行英文正文被判成公式」。公式模型是生成式的:喂一行英文散文进去它照样吐 LaTeX(把单词塞进 `\mathsf{}` 再套一层 `\boxed{\begin{aligned}}`),只看输出里有没有反斜杠、花括号根本分不出来 —— 之前一页英文正文会被整页标成公式,预览里的文字也被替换成那串垃圾。现在两道门:
174
+ - 判定前先挡:OCR 文本里有 ≥2 个「3 个字母以上的单词」且字母+空格占比 ≥75% → 判为散文,不喂模型(顺带省掉一次 0.1s 推理)。实测 `The following identity holds...`、`where the contour is taken...` 这类整行英文全部留在 `text`,公式碎片(`50(ν)=-−2`、`dw`、`π`)照旧当公式。
175
+ - 判定后再挡:LaTeX 里出现 ≥10 个连续字母(命令名之外),或 `\mathsf{` / `\texted{` / `\texttt{` 后面跟着 ≥3 个字母 —— 都是模型「在转写单词」的特征,判为正文。
176
+ - 已知限制:一行公式被检测框切成碎片时(横排碎片不参与合并),每片各自识别、各自判定,预览里会出现若干小公式行。碎片本身不再被当成正文丢弃,但拼不回整条公式。
177
+
178
+ ### 0.1.56(2026-09-11)
179
+ - **接入公式识别(PP-FormulaNet_plus-S)**。`XCorrectOcr.cpp` 识别完所有行后,若开启 `math`,逐行裁出图喂公式模型,判定为公式的行 `kind` 置为 `formula`、`text` 换成可读近似文本、`latex` 存原始 LaTeX。预览与 PDF 画的是 `text`,长按复制的是 `latex`(预览端已经按这个约定处理)。
180
+ - 新增 `XCorrectFormula.cpp`(模型装载 + 预处理 + 解码)与 `XCorrectLatex.cpp`(LaTeX → Unicode 近似文本)。三端桥接新增 `nativeInitFormula` / `nativeSetFormulaEnabled` / `nativeFormula`。
181
+ - 模型与词表由 [models/prepare_formula.sh](models/prepare_formula.sh) 一键生成,脚本里修了两个导出坑:
182
+ - `paddle2onnx` 导出 while 循环时,`If.3` 的 then 分支算出 rank-1 `[1]`、else 分支是标量,ONNX 要求一致,ORT 直接抛 `INVALID_ARGUMENT`。**随机输入能跑、真实图片才崩**,很容易误判成模型没问题。脚本在 `Add` 之后补 `Squeeze` 压回标量。
183
+ - 权重以 537 个 `Constant` 节点内联,ORT 官方量化器只认 initializer、对它完全无效(int8 量化后文件反而更大)。脚本自己按输出通道量化:101 个张量 221MB → int8,334MB 降到 194MB,**实测 token 输出与 float32 逐位一致**。
184
+ - 预处理按实测确定:灰度、等比缩放到 384 后左上角补 0、归一到 `[-1,1]`。补边是必须的,拉伸到 384 会把公式压扁(`\varrho^{-2\nu}` 会错成 `\varrho^{-2\mathcal P}`)。词表是字符级的,BPE 空格前缀(U+0120)要全部丢掉,否则会得到 `\zeta _ { 0 }` 这种每个字符带空格的写法。
185
+ - 公式判定是启发式:跳过汉字占比 > 30% 的行、跳过纯数字,要求 LaTeX 里出现反斜杠命令 / 花括号 / 上下标 / 等号之一。**行内嵌在文字中间的小公式不判为公式**,会原样留在 text——模型训练输入是独立公式块,整行文字喂进去结果不可靠。
186
+ - 公式模型约 294MB(自洽 float32)或 194MB(`--int8-only` 的量化版,ORT 加载不了),首次开启 `math` 时才装载,装载失败只记日志、不影响普通 OCR。两个文件都不进 git。
187
+ - 另外把公式模块的会话单例改成有意不析构:`Ort::Env` / `Ort::Session` 若作为静态对象在进程退出时析构,会和 ORT 运行库的卸载顺序撞车(主机实测抛 `mutex lock failed: Invalid argument` 后 `libc++abi` 直接 abort),移动端那是应用进程级崩溃。
188
+
189
+ ### 0.1.55(2026-09-11)
190
+ - 修「很白的纸处理完基本全白」。用户反馈纸略灰时效果可以,但纸本身很白时整片被做成死白。根因是纸面亮度归一的目标 248 对「纸面本来就在 240 附近」的实拍是**再往上顶**:顶完离 255 只剩 7 级,纸纹、反光、颗粒全被压没。现在纸面准备后 ≥ 200 时把目标降到 232(`kDocPaperTargetBright`),留出 23 级高光余量。
191
+ - 匀光的高光天花板跟着一起降:亮纸档原来把纸面顶到 246,纸面归一再想压回 232,两次调整互相抵消、纸纹反而被匀光抹掉一层。现在亮纸档的匀光上限用的是同一个 232。
192
+ - 自适应白场的余量从 12 级提到 18 级(`kDocWhiteHeadroom`):12 级对很白的纸同样只剩 7 级余量。
193
+ - 合成图实测(720×960,纸面带 ±9 级低频纸纹,纸面输入 170~245 六档):
194
+ | 纸面输入 | 修前 纸纹幅度 | 修后 纸纹幅度 | 越界率 |
195
+ | --- | --- | --- | --- |
196
+ | 170 | 11 | 11 | 0% |
197
+ | 185 | 13 | **17** | 0% |
198
+ | 200 | 12 | **16** | 0% |
199
+ | 215 | 9 | **15** | 0% |
200
+ | 230 | 8 | **15** | 0% |
201
+ | 245 | 3 | **13** | 0% |
202
+ 即很白的纸纸纹从 3 级恢复到 13 级、中间档普遍 +4~7 级,纸面落点从 247~249 降到 232~246,六档越界都是 0%。纸面低于 200 的图完全走原逻辑,暗光档行为一字未改。
203
+ - 新增 `XCORRECT_DOC_PAPER_BRIGHT_FROM` / `XCORRECT_DOC_PAPER_TARGET_BRIGHT` 两个 `-D` 口子,换参考图复标定不用改源码。
204
+
205
+ ### 0.1.54(2026-09-11)
206
+ - 修「预览叠字与图片上的文字大小对不上」。三端原先都把字号夹在 10–28(安卓是 `10×density`–`28×density` 像素、iOS 是 10–28 点、鸿蒙是 10–28 vp),而图片是按 `min(视图宽/图宽, 视图高/图高)` 缩放的,任何落在区间外的行字号都和图片对不上。现改为在**图片像素空间**绘制:字号 = 行框高 × 0.85,再乘画布缩放落到屏幕;大标题会真的变大,小字会真的变小。三端与 PDF 叠字共用同一个 0.85 系数,预览和导出一致。
207
+ - 新增 `minFontPt`(默认 10):等比换算后小于它才用它兜底,避免缩得太小看不清。只影响屏幕显示,不改坐标。
208
+ - 叠字不再截断成长文本加省略号:框不够宽时整行横向压扁(安卓压 `textScaleX`、iOS 先缩字号再压字距),保证文字完整。
209
+ - 叠字颜色从白字改成黑字,底色填充降到 25% 不透明度:白字在白纸或已被文档增强的灰阶图上几乎看不见,黑字在两种底上都清楚,也与 PDF 叠字的黑字一致。长按复制仍然保留。
210
+ - 识别行新增 `kind` 与 `latex` 字段(`text` / `formula` / `table_cell`),长按复制公式行时给 LaTeX 原文而不是近似文本。不开 `math` 时全是 `text`。
211
+ - 新增大框切行 `split_tall_boxes`:高度超过中位行高 2.2 倍的横排框,在框内做横向投影,用低于峰值 16% 的槽位把框切成多个行框。试卷、表格里被 DB 检成一整块的多行靠这一步拆开,不再被识别成一行乱码。至少切出两块才替换原框,否则保留原框不切。
212
+ - 新增多栏阅读顺序 `reorder_columns`:用所有行框的 x 覆盖求出「整列空白」并据此切栏,栏内自上而下排序。单栏文档找不到空白,顺序与从前完全一致,不影响原有单栏结果。
213
+ - 检测长边从 960 提到 1280,密集小字(试卷、表格里的小字号正文)检出率明显提高。
214
+ - 新增有线表格还原 `order_wire_table`:纯几何,不用模型。按像素投影找贯穿的横竖框线,把行框按「行 × 列」重新排序,并把落在表内的行标成 `table_cell`,让表格内容按自然阅读顺序输出。
215
+ - 公式模型实测后暂不内置,原因写在 [models/README.md](models/README.md):最小的 PP-FormulaNet-S 权重就有 221MB,超出体积预算;HuggingFace 只提供 Paddle 格式,要自己调社区导出链路才能出 ONNX;鸿蒙侧 ORT 1.16.3 只认 ONNX IR 8,导出工具链默认产出的高 IR 需要降级。`math` 选项与 `kind` / `latex` 字段已在接口上保留,模型就位即可接。
216
+ - 三端 aar / framework / har 已按新 C++ 重新编译,`XCorrectTable.cpp` 已进三端构建脚本。
217
+
218
+ ### 0.1.53(2026-09-11)
219
+ - 修「拍得很白的纸,处理后整片裁成死白」。用户反馈:纸略灰的实拍效果可以,但纸本身很白时处理后基本全白。原因是 PS 的色阶白场 188 是绝对值——纸面在色阶输入端的落点一超过 188,整片纸连同纸纹、反光一起被裁成 255,链后的纸面亮度归一(增益 <1)只能把 255 压到 248,压回来的是**一整块平色**,纹理已经丢了。
220
+ - 修法是**自适应白场**:纸面在色阶输入端的落点(`ps_bc_map(paperLevel)`)一旦超过用户白场,就把白场抬到「落点 + `XCORRECT_DOC_WHITE_HEADROOM`(默认 12 级,约 6% 余量)」,纸面因此落在白场之下,纸纹按近乎 1:1 保留:
221
+ - 纸面落点 205 → 白场 217 → 纸面输出 (205−10)/(217−10)×255 ≈ 238;
222
+ - 纸面比白场暗时白场仍是 188,后面照常走纸面亮度归一(把偏暗的纸抬到 248),原有行为一字未改。
223
+ - 走自适应白场时纸面归一**不再往上提**(增益封顶 1.0):抬白场留出的余量就是用来保纸纹的,再提一次会把余量吃掉。
224
+ - 合成亮纸图实测(纸面带 ±6 级低频纸纹,横条文字,纸面 170~235 五档):
225
+ | 纸面 | 处理前 纸面均值/纸纹幅度 | 修前 处理后 | **修后 处理后** |
226
+ | --- | --- | --- | --- |
227
+ | 170 | 169.5 / 11 | 244.8 / 30 | 244.8 / 30(不触发,与修前一致) |
228
+ | 185 | 184.5 / 11 | 246.3 / 24 | 246.3 / 24(同上) |
229
+ | 200 | 199.5 / 11 | 249.4 / **5** | **242.6 / 33** |
230
+ | 215 | 214.5 / 11 | 249.4 / **2** | **243.6 / 26** |
231
+ | 235 | 234.5 / 11 | 249.4 / **2** | **244.5 / 23** |
232
+ 即白纸档的纸纹幅度从 2~5 级(肉眼就是死白)恢复到 23~33 级,纸面落点 243~246 仍在参考图的 239~250 区间内;五档越界(≥254)都是 0%。
233
+ - 两张参考图复核(确认没退化,纸面落点反而更贴参考):湿巾 p25/p50/p90/均值 从 234/250/250/222.3 变成 **221/243/250/216.8**(参考 223/239/248/219.8);门票整页 71/167/220/248/149.6 变成 **67/159/209/242/144.2**(参考 89/164/206/251/153),票面白色抬头区开始出现纯白(4.3%,参考 7.1%);蓝色票根区均值 153.7 → 146.0(参考 154)。
234
+ - 新常量 `XCORRECT_DOC_WHITE_HEADROOM` 留了 `-D` 口子:余量给小了白纸还是会被裁一片,给大了纸面会停在浅灰。三端 aar / framework / har 已按新 C++ 重新编译。
235
+
236
+ ### 0.1.52(2026-09-11)
237
+ - **文档增强的色调链换成按 Photoshop 标定的固定值**。用户按 PS 调好的四个调整原样搬进 C++:亮度 −10、对比度 +71(PS「亮度/对比度」非旧版,范围 −150..150 / −50..100)→ 黑白六色权重(红 19、黄 50、绿 21、青 60、蓝 27、洋红 56)→ 色阶(输入黑场 10、中灰 1.00、输入白场 188,即 [10,188] 拉满到 [0,255])。原来的「双峰锚点色调曲线 + Rec.601 去色」整段删除,`XCORRECT_DOC_PAPER_K` / `XCORRECT_DOC_INK_K` 与不再有人调用的 `desaturate_rgba` 一并移除。用户提供的是「纯文本 + 有风景照片/彩色票根」两类场景的折中值,两条参考图(原图 + PS 成图)都做了逐项比对,见文末。
238
+ - 三处算法要点,都不是「看起来像」的近似:
239
+ - 亮度/对比度是 PS 非旧版算法,不是旧版的「线性偏移 + 会裁两端的斜率」。亮度端点固定(0→0、1→1),正向是「低段增益射线 σ=2^(b/110)、到 y=0.5 后一段三次 Hermite 收到 (1,1)、端点斜率 τ 比中段小」,负向是正向曲线的**严格反函数**(PS 就是这么算的,不是镜像),用固定 64 步二分求逆;对比度是绕 0.5 的二次 S 曲线 β = 1 − 0.0076c,端点同样固定。所以 +71 提对比不会把纸面顶爆、也不会把墨迹切死(c=100 时中段斜率也只有约 1.76)。
240
+ - 黑白用 max/mid/min 三段分解:灰底 = min,复色段 (mid−min) 按 min 是哪个通道吃青/洋红/黄,单色段 (max−mid) 按 max 吃红/绿/蓝。中性色完全不受权重影响;纯红/黄/绿/青/蓝/洋红正好等于对应权重 ×255,与 PS 行为一致(这部分与 PS CS 的公开公式互证)。
241
+ - 锐化**排在最后**(纸面亮度归一之后)。放链内会先造出比纸面更亮的字边过冲,再被纸面归一整体提亮顶到 255 裁平——合成图实测 71.7% 的纸面像素被打满;放最后则锐化自身的压暗限幅与亮部软上限在最终亮度域上如实生效,纸面越界归零。
242
+ - 保留 `document_auto_prepare_rgba`(白平衡去黄偏 + 分块匀光)作为**拍摄条件**修正,另加一道**纸面亮度归一** `paper_target_rgba`(目标 `XCORRECT_DOC_PAPER_TARGET` = 248、增益限制在 0.90~1.35)。这一版顺手修了匀光的两处毛病:
243
+ - **参考基准从「块背景中位数」改成「块背景的 0.85 高分位」**。票证这类「照片 + 大色块 + 白纸」的页面里照片块可能占一半以上,中位数会被照片拖低(实测门票页中位数 130,只有纸面 185 的七成),匀光于是把纸面和大色块一起往照片的亮度上压(实测蓝色票根区 −8 级),再被色阶的 1.43 倍斜率放大成 −17 级。
244
+ - **加内容保护**:匀光增益按像素亮度加权(≥0.72×纸面基准全量、≤0.42×完全不施加),只修纸面/背景的照度不均,不再把照片、大面积色块、墨迹当背景一起缩放。
245
+ - 匀光强度解耦成 `XCORRECT_DOC_FLATTEN`(默认 0.50,原先是硬编码 0.88)。强度下调是因为「浅色大色块」和「被阴影压暗的纸面」在算法上无从区分:0.88 时票根区被抬高 15%(+19 级),0.50 时约 8 级,纸面匀光仍能修掉一半以上的明暗差。
246
+ - 纸面归一的增益上限卡在 1.35 而不是 2.0:目标 248 离 255 只剩 2.8% 余量,提得越猛越容易把纸面亮部裁平(1.94 倍时合成图 71.7% 的纸面像素被打满 255)。代价是非常暗的图(纸面 ≲130)会停在浅灰而不是纯白——「宁可不够白也不裁平」,与用户此前反复要求的「别丢纸纹和反光」一致。
247
+ - 想严格复刻 PS(关掉白平衡、匀光、纸面归一)编译期加 `-DXCORRECT_DOC_KEEP_AUTO_PREP=0` 即可;所有 PS 值(`XCORRECT_PS_BRIGHTNESS` / `CONTRAST` / `BW_*` / `LEVELS_*`)都留了 `-D` 覆盖口子,换参考图复标定不用改源码。色调链另有独立入口 `ps_tone_chain_rgba`,主机端对拍不必绕 warp。
248
+ - 主机端探针(`#include` 直接抽取 `XCorrectCore.cpp` 编译,避免手抄漂移)实测:
249
+ - 六色权重映射:纯红 255→**48**(19%)、纯黄→**128**(50%)、纯绿→**54**(21%)、纯青→**153**(60%)、纯蓝→**69**(27%)、洋红→**143**(56%);中性 0/64/128/200/255 全部恒等。
250
+ - 亮度/对比度曲线:0→0、16→8、64→43、128→116、160→160、192→196、224→228、255→255,端点固定、单调;色阶:10→0、11→1、20→14、100→129、187→254、188→255;整条链(灰阶)32→11、128→152、160→215、188→255,全表单调不减。
251
+ - 合成文档图逐点核对(暖光纸面 RGB 比 1 : 0.972 : 0.822,横条文字;另测一档手影 0.74→1.0):纸面 120/140/160/180/200 档最终落在 **187 / 239 / 250 / 250 / 250**,纸面越界(≥254)**0%**;带手影档落在 133 / 175 / 214 / 221 / 233,越界同样 0%。
252
+ - **与用户两张参考图的对拍**(参考图是同内容 PS 成图的截图,口径统一为:原图取纸面内区,跑我们完整文档增强,再比区域分位数):
253
+ - 纯文本(湿巾包装):参考 p25 223 / p50 239 / p90 248 / 均值 219.8 / 纯白 0.2%;我们 **234 / 250 / 250 / 222.3 / 0%**。
254
+ - 风景票证整页:参考 p25 89 / p50 164 / p75 206 / p90 251 / 均值 153 / 纯白 7.1%;我们 **71 / 167 / 220 / 248 / 149.6 / 0%**(参考图那 7.1% 纯白来自票面白色抬头区,我们归一后停在 248,差 7 级)。
255
+ - 同一张票证的蓝色票根区(大块中间调,最能看出匀光是否把内容当背景拉平):参考 p25 155 / p50 164 / p75 168 / 均值 154;我们 **142 / 171 / 183 / 153.7**。
256
+ - 把两张参考图反查回输入(用链的逆推)得到「用户 PS 输入」的分位数,与我们手上原图裁剪区相差不到 10 级(参考图是微信转发件 + PS 截图,输入本身已被压缩/重采样过),所以上面几级的差异主要来自输入而不是链路。
257
+ - 算法出处与验证状态:PS 非旧版亮度/对比度取自公开的逆向标定结果(15bit 全档扫描,450 张 15bit 捕获全部落在 1 LSB15 内),黑白公式与另一份 PS CS 的公开公式互证。本机 PS 25.11 的脚本对拍**没跑通**(`do javascript` 在本机不执行,脚本未落地任何文件),所以没有逐像素对拍数据;要复验可以拿一张灰阶 ramp 图在 PS 里跑一遍同样的四个调整,再喂给 `ps_tone_chain_rgba` 比表。
258
+ - 三端 UI 注释(Android / iOS)同步改成「先白平衡 + 匀光,再按 PS 标定色调链出灰阶黑白」。
259
+
260
+ ### 0.1.51(2026-09-11)
261
+ - 修安卓「原图扫描 / 文档增强」两个胶囊按钮紧贴无间距:`rebuildModeChips` 把 chip 直接 `addView` 进 `modeStrip`,既没给 chip 设 margin,`modeStrip` 也没设 `divider`/`showDividers`,两个按钮就贴在一起。iOS 靠布局算 `gap: 12`、鸿蒙靠 `Row({ space: 12 })`,所以只有安卓缺间距。修法是给非最后一个 chip 设 `marginEnd = dp(12)`,与另外两端对齐。只给非最后一个加:`modeStrip` 是 `WRAP_CONTENT` 且居中,末尾也加会让整组偏左半个间距。
262
+ - 对照检查了同一屏的分辨率档 `qualityChip`,它用 `LinearLayout.LayoutParams(0, WRAP, 1f)` 按权重平分整行宽度,等分格子之间天然不需要间距,与胶囊按钮是两种布局模式,不受本次改动影响。
263
+
264
+ ### 0.1.50(2026-09-11)
265
+ - 修鸿蒙「拍照瞬间图片向左转 90°、等确认框出来才回正」:这是 0.1.49 为优化卡顿把分析帧缩到 640×480 后,连带把 `freezeStillPath` 的冻结预览改成优先走 `createPixelMapFromSurfaceSync`(绑全分辨率预览流)时引入的回归。surface 抓出来的是**传感器方向的原始像素**,而那条新路径调的 `savePixelMapJpeg` 只负责编码、完全不转正;原来的 NV21 路径走 `saveNv21Jpeg`,内部会按 `sensorOrientation` 做 `rotateSync`。`sensorOrientation` 默认 90,于是冻结预览横躺,等 `captureHdPath` 拿到带 EXIF 转正的高清照片覆盖后才回正。修法是把转正搬到 surface 抓拍路径上:按 `sensorOrientation` 归一到 0/90/180/270 后 `rotateSync`,前摄再 `flipSync` 镜像,与 `saveNv21Jpeg` 完全同一套约定(该约定改动前一直在用,方向可靠)。
266
+ - `rotateSync` 未必对 surface 抓拍得到的 PixelMap 可用(`saveNv21Jpeg` 是显式传 `editable: true` 创建的 PixelMap 才旋转的,SDK 文档对 `rotateSync` 只标注 401/501 未承诺可编辑性),所以整段包 try:一旦旋转或落盘失败就退回 `lastFrame` 路径,那条走 `saveNv21Jpeg`,转正已被验证可靠,最坏只是冻结画面偏糊(640×480),绝不会方向错。同时把 `surfaceMap.release()` 移进 `finally`——原先它在 `rotateSync` 之后,一旦旋转抛异常这张全分辨率 PixelMap 就永不释放,每次拍照泄漏一次。
267
+
268
+ ### 0.1.49(2026-09-10)
269
+ - 新增画质模式菜单:相机预览与缩略图条之间加「原图扫描 / 文档增强」两态切换,三端样式统一(选中绿底黑字胶囊、未选中透明底白字细描边),默认文档增强。`原图扫描` 保留彩色只做轻提亮 + 轻锐化;`文档增强` 走去黄偏 → 分块匀光 → 双峰锚点色调曲线 → 锐化 → 按 Rec.601 亮度转灰阶黑白(不做二值化,保留层次)。模式只在取景态可切,确认/结果态隐藏,避免给出一个不会改变当前预览的开关。C++ 侧新增 `EnhanceMode` 枚举与 `enhance_by_mode`,`nativeWarp` 的 `enhance` 参数改为 `mode`,另加 `nativeEnhanceMode` 供不拉正路径使用。
270
+ - 修实时框中间的绿色填充:三端都改成只描边不填充(Android 去掉 `fillPaint` 的 `drawPath`、iOS 只 `stroke()`、鸿蒙 Polyline `fillOpacity(0)`)。填充会盖住预览内容,看不清纸面实际位置。
271
+ - 缩略图条下移贴近底部拍照工具栏:Android 下内边距 12→4dp、上 12→8dp;鸿蒙 List 高 88→74、上 12→6、下 12→4。模式菜单插在预览与缩略图之间,两者间距由菜单自然撑开。
272
+ - 修「增强后对比度偏强、字迹发死黑」。分阶段探针(用原图墨迹掩码固定采样同一批像素)测出真正的元凶不是色调曲线而是锐化:曲线对对比度只贡献 +2.5,锐化贡献 +38.7——字迹像素被亮纸面包围,模糊值远高于字心,非锐化掩模的 `diff` 是大负值(实测墨迹 46 → 模糊 93 → `add≈-28`),把墨迹从 46 直接砸到 18,死黑率从 0% 涨到 1.40%。修法是给锐化加压暗限幅(`darkenLimit=6`)和提亮天花板(`kWhiteCeiling=250`),只限两端、不伤中间过渡带。同时把锐化强度从 `kDocStrength` 解耦成独立常量 `kDocSharpen`(原先两者共用一个系数,降对比度会连带降清晰度,与需求相反)。纸面亮度 160 档的标定结果,分两组口径:分阶段探针(固定掩码)测得对比度增量 +41.3 → **+28.3**、锐化对墨迹的压暗 27.7 级 → 9.9 级、死黑率 1.40% → **0%**;全图清晰度指标测得边缘梯度 6.36 → **6.96**、拉普拉斯方差 3670 → **3868**、过曝 0.11% → **0%**。即对比度降下来、清晰度和过曝表现同时变好。曲线侧另把 `targetPaper` 0.38→0.26、`targetInk` 0.22→0.15。四个常量都留了 `-D` 覆盖口子便于复标定。
273
+ - 修安卓裁剪后清晰度不如预期:相机图在 `processFile` 里已被 `saveToFile(q=95)` 覆盖写回工作文件,而 `confirmReview` 又从该文件按 4096 重新解码——`preview` 与工作文件几何完全一致,这次重解码拿不到任何额外像素,只多付一代 JPEG 压缩损失。改为相机源直接用 `preview`,相册源仍重解码(它在 `processFile` 只解到 1600,重解码到 4096 才有真实收益)。
274
+ - 修鸿蒙实时框卡顿。根因是每帧要在 UI 主线程上跑四次 ArkTS 图像 API:`createPixelMapSync`(NV21→RGBA 全帧)→ `scaleSync` → `rotateSync` → `readPixelsToBufferSync`,再把 RGBA 缓冲跨语言传给 native;ArkTS 的 `enqueue` 只是 Promise 链,并不切线程,ORT 推理期间整个 UI 线程被冻结(主机实测 256 模型推理 68.5ms,手机更久)。现新增 native 入口 `detect_from_nv21_live` / `nativeDetectLiveNv21`,在 C++ 里一趟完成 NV21→RGB(BT.601)+ 按传感器朝向转正 + 双线性重采样到 256×256,四次 ArkTS API 往返和中间 RGBA 缓冲的跨语言拷贝全部省掉。前摄仍需镜像(模型预处理不做镜像),故前摄保留原 RGBA 路径。另把分析流 profile 从 1920×1440(2.7MP)降到 640×480,单帧像素量降到 1/9;预览流不受影响,仍是 1920×1440。因分析帧变小,`freezeStillPath` 的冻结预览改为优先走 surface 抓拍(绑的是全分辨率预览流),`lastFrame` 退为兜底,避免冻结画面变糊。
275
+ - NV21→RGB 转换用 Python 参考实现对拍验证:把 `preprocess_bgr_nchw_nv21` 函数体直接从源码抽取编译(避免手抄漂移),在 0/90/180/270 四个旋转角上与参考实现逐位比较,`max|diff| = 0.000000`,含行尾 stride 填充的场景一致。
276
+ - 顺带修正上一轮的错误结论:曾推断「鸿蒙 ORT 1.16.3 跑不了 opset 16 的找角模型」。实测 ORT 1.16.3 能正常加载并推理,真实纸面 min-peak 0.636~0.873、负样本 ≤0.033,与 ORT 1.29 一致;`libonnxruntime.so` 的 strings 里也有完整的 8 条 ellipsis 错误消息。鸿蒙实时框不出的真实原因是帧格式判错:分析流 profile 是 `CAMERA_FORMAT_YUV_420_SP`,交付的是 NV21 原始像素,而 `decodeBufferToRgba` 用的 `createImageSource` 只认 JPEG/PNG 编码流,喂 NV21 必然抛异常返回 null,于是每帧 `liveMiss++`,框永远出不来;拍照路径正常是因为它走 `photoOutput.photoAvailable` 拿真实照片文件,冻结预览正常是因为 `freezeStillPath` 本来就有 `isJpegBuffer` + NV21 分支,只有实时检测漏了这一支。
277
+ - 三端 aar / framework / har 均已按新 C++ 重新编译,`nativeEnhanceMode`、`nativeDetectLiveNv21` 等新符号已核对导出,Android JNI 导出与 Kotlin `external` 声明、Harmony NAPI 注册与 `.d.ts` 三处逐一对齐。
278
+
279
+ ### 0.1.48(2026-09-10)
280
+ - 撤销 0.1.47 给实时路径加的「传统 C 算法兜底」,实时框改为**只走找角模型**。0.1.47 为了修鸿蒙引入了三档分流,其中「模型还没成功检出过就先跑模型、没结果再补跑传统」这一档直接导致安卓/iOS 识别率暴跌:开机对准文档之前的头几帧必然检不出纸,传统算法就在小框、阴影边缘上凭空拼出矩形,`note_fallback(true)` 连续累加 3 次后把模型永久判为「不可靠」,此后整个会话都只跑传统算法,于是实时框乱跳、大块纯色和手指蒙镜头也能出框。现在实时路径彻底不再调用传统算法:模型检出就画框,检不出就不画,纯色/手指/阴影一律 `found=false`。拍照后的编辑确认框仍走 `detect_quad`(模型 + 传统 + 证据门禁),兜底能力保留在静图路径上,功能没有缺失。
281
+ - 用真实模型实测标定后把采纳门槛 `kMinScore` 从 0.30 提到 0.40。跨 ORT 1.16.3 与 1.29、跨全部合成场景可复现的硬事实是负样本上界:纯黑 0.0012 / 纯白 0.0017 / 纯灰 0.0013 / 纯红 0.0011 / 手指蒙镜头 0.0015 / 阴影边缘 0.0011 / 木纹桌面 0.0017 / 随机噪声 0.0067,最高 0.0121,0.40 门槛是其 33~59 倍余量。没有取更高的 0.50+,是为真实暗光、倾斜、低对比纸面保留召回:合成纸面的分数会随矩形边界差 0.04 从 0.002 跳到 0.744,落在模型决策边界上,不能拿它当调参依据,所以只按可复现的负样本上界抬高,不做过度拟合。
282
+ - 修 0.1.46 给模型结果叠加证据门禁造成的漏检:`detect_quad_ex` 里模型检出后还要求 `modelScore >= 0.72` 或像素级证据通过,等于把 0.40~0.72 分的合法低对比纸面又推回传统算法。实测模型对纸桌亮度差仅 2 级的极端低对比文档也给 0.72~0.91 分,说明 `kMinScore` 这一道关已经足够,模型结果直接采信。证据门禁保留给传统算法路径,它本来就是为「传统算法凭空拼框」设计的,实测禁用后渐变桌面会全部误检。
283
+ - 修鸿蒙实时框不出的真正原因:**帧格式判错**,与模型、ORT 版本都无关。鸿蒙实时帧来自绑成 `PreviewOutput` 的 `ImageReceiver`,profile 申请的是 `CAMERA_FORMAT_YUV_420_SP`,交付的是 **NV21 原始像素**,而 `decodeBufferToRgba` 用 `image.createImageSource(buffer)` 解码——它只认 JPEG/PNG 编码流,喂 NV21 必然抛异常返回 null,于是每帧 `liveMiss++`,框永远画不出来。拍照路径正常是因为它走 `photoOutput.photoAvailable` 拿真实照片文件;冻结预览路径也正常,因为 `freezeStillPath` 里本来就有 `isJpegBuffer` 判别 + `stripNv21Stride` + `saveNv21Jpeg` 的 NV21 分支,只有实时检测路径漏了这一支。现新增 `decodeNv21ToRgba`(`createPixelMapSync` + `srcPixelFormat=NV21` → `scaleSync` 降到 512 → 按 `sensorOrientation` 转正 → 前摄镜像 → `readPixelsToBufferSync`),实时路径按 `isJpegBuffer` 分流:真 JPEG 走原解码,NV21 走新解码。
284
+ - 顺带修正上一轮对鸿蒙的错误结论:曾推断「鸿蒙 ORT 1.16.3 跑不了 opset 16 的找角模型(含 20 个带 ellipsis 的 Einsum)」。实测 ORT 1.16.3 能正常加载并推理该模型,真实纸面 min-peak 0.636~0.873、负样本 ≤0.033,与 ORT 1.29 结果一致;`libonnxruntime.so` 的 strings 里也有完整的 8 条 ellipsis 错误消息。据此删除了为这个错误推断而写的 `corner_model_proven` / `corner_model_note_fallback` / lose-streak 降级 / `copy_rgba_rot` / `kLiveWorkEdge` / `try_model` 等全部死代码。
285
+ - 硬故障短路改到 `detect_by_model` 与 `detect_by_model_buf` 内部:连续 3 次 `Run` 抛异常或输出形状非法即停用模型,不再每帧白付一次推理;热力图峰值低属正常「没对准纸」,不计入硬故障。
286
+
287
+ ### 0.1.47(2026-09-10)
288
+ - 修三端「模型加载失败后每帧重试」拖垮实时帧率:`ensureCornerModel` 原先只判断 `if (modelReady) return`,加载失败后 `modelReady` 恒为 false,于是**每一帧**都会重新走一遍「从 rawfile/assets/Bundle 释放 4.7MB 模型 → `nativeInitModel` 重新加载」。iOS 更严重:`guard let caches ... else { return }` 在置位之前就返回,连失败状态都没记住。在 150ms 节流下每帧白付几百毫秒,实时框自然出不来。现三端都加 `modelAttempted` 标志(iOS 置于所有提前 return 之前),一次会话只尝试一次,失败就靠传统兜底跑完整个会话,重进页面/重启 App 才再试。
289
+ - 修鸿蒙实时框不出:0.1.46 把三端实时路径统一成「只跑 256 找角模型、不再跑传统管线」,但没留兜底。鸿蒙的 ORT 是运行时 `dlopen` 的 1.16.3(安卓/iOS 是 1.28.0),找角模型一旦不可用,实时路径就永远返回 false,框再也画不出来;而拍照后的编辑框走 `detectRgba`(模型失败仍有传统算法兜底)所以正常,表现为「实时看不到框、拍照后却有编辑框」。现按三档分流,兼顾「能出框」与「够流畅」:
290
+ - 模型已证明可用(本次会话成功检出过一次):每帧只跑 256 热力图,本帧没纸就返回不画框,绝不补跑传统检测。这是安卓/iOS 的快路径,流畅度与 0.1.46 一致。
291
+ - 模型不可用(加载失败 / 连续硬故障):直接走传统检测,一次模型推理都不白付。
292
+ - 模型能加载却还没成功检出过:先跑模型,没结果就补跑传统。这一档专门兜住「加载成功、`Run` 不报错、却始终算不出纸面」的隐蔽故障——上一版「纯色画面也能出实时框」正说明鸿蒙走的就是传统路径,属于这一档。
293
+ 回退时工作图长边从静图的 800 降到 400(实测 720p 帧约 27ms),且证据门禁照常生效,纯色/无纸仍不会误检。ORT 层用「模型输给传统」的次数做安全降级信号:连续 3 帧「模型没检出而传统检出」即认定模型在本平台不可靠,此后锁定纯传统路径,不再每帧白付推理;对着白墙时传统同样检不出,计数不增长,故不会误降级。实测该档模型只在前 3 帧被调用,之后归零。
294
+ - 修实时兜底每帧重复推理:`detect_quad_ex` 内部本来就会先试一次模型,实时兜底路径外层已经试过,等于每帧白付两次推理。给它加 `try_model` 参数,兜底调用传 false 跳过内部尝试,每帧模型调用从 2 次降到 1 次(降级后为 0 次)。
295
+ - 修增强后图片偏黑:0.1.46 的色调曲线 `gamma = 1 + 0.30 × strength`(strength 60 时约 1.18)方向是反的——gamma>1 的幂函数把中间调整体压向墨迹一侧,实测字迹与纸面之间的浅灰平均压暗 4.6 级、高光 235 级被压到 224.6,肉眼就是整页发灰发黑。文档增强的正确方向是把纸面提干净:gamma 改为 `1 - 0.14 × strength`(<1,中间调向纸白提亮),高光斜率 0.50→0.70(少压高光、保住纸纹),墨黑压缩 0.42→0.30(字迹靠锚点压深即可,不必再靠曲线),默认强度 60→50。实测同场景 mean 143.9→157.3、纸面均亮 160.7→179.6(原先是 143.9→109.0 一路压暗),动态范围仍变宽、黄偏仍消除约 8 成、零过曝。
296
+ - 修 iOS 只有 1 档分辨率:原先 `collectPhotoSizes` 只读当前 `activeFormat.supportedMaxPhotoDimensions`,而该属性是「单个 format」的——iOS 上一个 4:3 format 通常只给 1 项(另一项是 16:9,被 4:3 过滤掉),所以只剩一档;安卓/鸿蒙枚举的是硬件全部 JPEG 输出尺寸,故有 5 档。跨 format 枚举要切 `activeFormat`,而 0.1.43/0.1.44 记录过切 format 未 lock 直接闪退。改为:只读遍历 `device.formats` 取传感器最大 4:3 尺寸(不切 format,零闪退风险),档位表达「输出分辨率」——始终按传感器最大尺寸拍摄,落盘前按所选档位长边降采样(快门时快照档位,避免工作线程读主线程状态)。长边按 32 对齐、封顶到 `warpMaxEdge`(否则 48MP 设备会标 8064 而实际只出 4096,标签虚高)。实测 12MP/48MP/iPad 8MP/5MP 各传感器均给出 5 档,切档不再重配会话。
297
+ - 鸿蒙实时帧解码长边 720→512:模型只要 256×256,回退路径内部也按 400 工作,720 让每帧多做一倍以上的 JPEG 解码、`rotateSync` 与 readPixels。
298
+
299
+ ### 0.1.46(2026-09-10)
300
+ - 修纯色误检:黑色/任意纯色画面不再凭空识别出纸张边框。`scan_edge` 原先 `bestScore` 初值 `-1`,纯色图每条扫描线梯度为 0,`0 > -1` 成立导致返回 margin 位置拼出内收矩形,而几何打分对完美轴对齐矩形几乎满分,在零边缘证据下也过 1.35 门槛。新增证据门禁 `measure_evidence`/`evidence_ok`:量四条边「框外亮度 - 框内亮度」带状均值阶跃与边梯度,取中位数并统计达标边数,至少 2 条边达标才认定找到纸;用带状均值而非逐点绝对差,随机噪声的内外差会相互抵消,只有连贯边界才有稳定阶跃。找角模型本身对纯色已正确拒绝(热力图峰值约 0.003,远低于 0.30 阈值)。
301
+ - 实时框提速:三端原先不一致——iOS 走 256 模型,Android/Harmony 却每帧跑完整 800px 传统管线(本机实测 47–144ms)。现统一只跑 256 热力图模型。Android 相机分析帧不再 `toBitmap → rotateBitmap → scaleToMaxEdge → bitmapToRgba`(四次 Bitmap 分配 + 69 万像素 Kotlin 逐像素循环),改为直接取 RGBA 分析缓冲原始字节 + rowStride,native 在重采样到 256×256 时顺带按 rotationDegrees 转正,把每帧遍历压到 6.5 万像素。节流 Android 220→150ms、Harmony 240→150ms,实时平滑系数三端统一 0.42/0.66→0.5。
302
+ - 裁剪后画质智能化:新增纸面增强 `enhance_document_rgba`,在 warp 之后调用(此时纸已占满画面,统计口径才成立)。文档亮度是双峰分布(墨迹峰 + 纸面峰),不能用分位数当中灰——中位数落在纸峰上、用它定 gamma 会把字迹整片压黑;改为分别找两个峰当锚点重建曲线。流程:白平衡(把纸面峰附近像素拉中性,并做亮度归一,只改色度不改亮度,避免去黄偏时把纸压暗)→ 分块光照均匀化(按每块背景 0.85 分位归一,去阴影和台灯亮斑,带高光软膝防死白)→ 双峰锚点连续色调曲线(墨迹内部线性保留层次、高光半斜率压缩保住纸纹)→ 亮度非锐化掩模轻锐化(等量加回三通道不引入彩边)。
303
+ - 修原增强时机:拉正路径原先在 warp 之前对未拉正的整帧做 `auto_enhance`(统计混入桌面背景)再 `saveToFile` 覆盖、warp 又编码一次,双重 JPEG。现拉正路径的增强移入 warp 内部(单次编码),`auto_enhance` 只保留给 `stretch: false` 的非拉正路径(画面仍含背景,用通用增强安全提亮)。
304
+ - 新增 native 入口:`nativeDetectLive`(带 stride + 顺时针转正角,直接从相机缓冲找纸)、`warp_from_rgba` 加 `enhance` 强度参数;`detect_from_rgba` 支持 stride 并在返回 JSON 里附 `evidence`(step/energy/sides)。三端 aar / framework / har 已重新编译。
305
+
306
+ ### 0.1.45(2026-09-09)
307
+ - iOS 实时框改为相机 BGRA 直接下采 + 只跑找角模型,不再每帧 CIContext 出图;图标字体按文件真实名运行时注册,避免全是问号。
308
+
309
+ ### 0.1.44(2026-09-09)
310
+ - iOS 分辨率档不再切换 `activeFormat`,只在当前预览 format 上设 `maxPhotoDimensions`,避免未 lock 闪退。
311
+
312
+ ### 0.1.43(2026-09-09)
313
+ - 修 iOS 打开相机 / 拍照闪退:分辨率必须落在当前 format 的 `supportedMaxPhotoDimensions` 里,改 format 先 `lockForConfiguration`。
314
+
315
+ ### 0.1.42(2026-09-09)
316
+ - 拍照后先抽样读亮度和对比度,再按纸面情况提亮、拉对比;不另加图像库,走已有 C++ 核。
317
+
318
+ ### 0.1.41(2026-09-09)
319
+ - 取景改为 4:3 居中,上下黑边放菜单,不再全屏铺满。
320
+ - 顶栏下列出相机从高到低最多 5 档分辨率(默认超高清),可点选拍照尺寸。
321
+ - 扫描时实时画矫正边框,节流约 4fps;拍照确认框与实时识别一致。
322
+
73
323
  ### 0.1.40(2026-08-20)
74
324
  - 安卓确认预览叠字按 10–28dp 计算,与 iOS 点、鸿蒙 vp 对齐,避免高分屏把 28 当成 28px。
75
325
  ### 0.1.39(2026-08-20)