@veltra/desktop 1.7.12 → 1.7.15

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 (190) hide show
  1. package/dist/components/batch-edit/batch-edit-form.js +9 -3
  2. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  3. package/dist/components/batch-edit/batch-edit-list.js +2 -1
  4. package/dist/components/batch-edit/batch-edit-list.js.map +1 -1
  5. package/dist/components/batch-edit/batch-edit.js +57 -30
  6. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  7. package/dist/components/batch-edit/helper.d.ts +1 -2
  8. package/dist/components/batch-edit/style.d.ts +1 -0
  9. package/dist/components/batch-edit/style.js +1 -0
  10. package/dist/components/batch-edit/style2.css +14 -0
  11. package/dist/components/batch-edit/use-dialog-effect.js +20 -0
  12. package/dist/components/batch-edit/use-dialog-effect.js.map +1 -0
  13. package/dist/components/batch-edit/use-edit-state.js +22 -3
  14. package/dist/components/batch-edit/use-edit-state.js.map +1 -1
  15. package/dist/components/batch-edit/use-handlers.js +5 -0
  16. package/dist/components/batch-edit/use-handlers.js.map +1 -1
  17. package/dist/components/batch-edit/use-shortcut-key.js +5 -2
  18. package/dist/components/batch-edit/use-shortcut-key.js.map +1 -1
  19. package/dist/components/condition-editor/core/evaluator.d.ts +4 -5
  20. package/dist/components/contextmenu/api.d.ts +1 -2
  21. package/dist/components/contextmenu/di.d.ts +2 -3
  22. package/dist/components/file-viewer/file-viewer.js +21 -14
  23. package/dist/components/file-viewer/file-viewer.js.map +1 -1
  24. package/dist/components/file-viewer/helper.js +2 -0
  25. package/dist/components/file-viewer/helper.js.map +1 -1
  26. package/dist/components/file-viewer/previewers/ofd-previewer.js +196 -0
  27. package/dist/components/file-viewer/previewers/ofd-previewer.js.map +1 -0
  28. package/dist/components/file-viewer/style2.css +27 -0
  29. package/dist/components/loading/directive.d.ts +1 -2
  30. package/dist/components/message/message.d.ts +1 -2
  31. package/dist/components/message-confirm/message-confirm.d.ts +1 -2
  32. package/dist/components/notification/notification.d.ts +1 -2
  33. package/dist/components/table/node/col.js +19 -0
  34. package/dist/components/table/node/col.js.map +1 -1
  35. package/dist/components/table/table-cell.js +2 -0
  36. package/dist/components/table/table-cell.js.map +1 -1
  37. package/dist/components/table/table-foot.js +2 -0
  38. package/dist/components/table/table-foot.js.map +1 -1
  39. package/dist/components/table/table-head.js +1 -0
  40. package/dist/components/table/table-head.js.map +1 -1
  41. package/dist/components/table/table-row.js +2 -0
  42. package/dist/components/table/table-row.js.map +1 -1
  43. package/dist/components/table/use-columns.d.ts +1 -2
  44. package/dist/components/table-editor/style2.css +23 -3
  45. package/dist/components/table-editor/table-editor.js +213 -63
  46. package/dist/components/table-editor/table-editor.js.map +1 -1
  47. package/dist/components/tip/style2.css +63 -0
  48. package/dist/components/tip/tip.js +6 -1
  49. package/dist/components/tip/tip.js.map +1 -1
  50. package/dist/index.d.ts +4 -4
  51. package/dist/install.d.ts +3 -3
  52. package/dist/packages/ofd-core/dist/color.js +69 -0
  53. package/dist/packages/ofd-core/dist/color.js.map +1 -0
  54. package/dist/packages/ofd-core/dist/ctm.js +55 -0
  55. package/dist/packages/ofd-core/dist/ctm.js.map +1 -0
  56. package/dist/packages/ofd-core/dist/error.js +14 -0
  57. package/dist/packages/ofd-core/dist/error.js.map +1 -0
  58. package/dist/packages/ofd-core/dist/font.js +384 -0
  59. package/dist/packages/ofd-core/dist/font.js.map +1 -0
  60. package/dist/packages/ofd-core/dist/index.js +6 -0
  61. package/dist/packages/ofd-core/dist/number.js +13 -0
  62. package/dist/packages/ofd-core/dist/number.js.map +1 -0
  63. package/dist/packages/ofd-core/dist/page-objects.js +181 -0
  64. package/dist/packages/ofd-core/dist/page-objects.js.map +1 -0
  65. package/dist/packages/ofd-core/dist/parse.js +65 -0
  66. package/dist/packages/ofd-core/dist/parse.js.map +1 -0
  67. package/dist/packages/ofd-core/dist/render.js +361 -0
  68. package/dist/packages/ofd-core/dist/render.js.map +1 -0
  69. package/dist/packages/ofd-core/dist/xml.js +199 -0
  70. package/dist/packages/ofd-core/dist/xml.js.map +1 -0
  71. package/dist/packages/ofd-core/dist/zip.js +93 -0
  72. package/dist/packages/ofd-core/dist/zip.js.map +1 -0
  73. package/dist/style.d.ts +1 -1
  74. package/dist/style.js +1 -1
  75. package/dist/types/action.d.ts +7 -8
  76. package/dist/types/animation.d.ts +4 -5
  77. package/dist/types/auto-complete.d.ts +4 -5
  78. package/dist/types/badge.d.ts +4 -5
  79. package/dist/types/batch-edit.d.ts +15 -10
  80. package/dist/types/breadcrumb.d.ts +6 -7
  81. package/dist/types/button.d.ts +5 -6
  82. package/dist/types/calendar.d.ts +7 -8
  83. package/dist/types/card.d.ts +7 -8
  84. package/dist/types/cascade.d.ts +6 -7
  85. package/dist/types/check-tag.d.ts +4 -5
  86. package/dist/types/checkbox-group.d.ts +3 -4
  87. package/dist/types/checkbox.d.ts +5 -6
  88. package/dist/types/code-editor.d.ts +5 -6
  89. package/dist/types/collapse.d.ts +6 -7
  90. package/dist/types/condition-editor.d.ts +11 -12
  91. package/dist/types/contextmenu.d.ts +5 -6
  92. package/dist/types/css-transition.d.ts +4 -5
  93. package/dist/types/date-panel.d.ts +3 -4
  94. package/dist/types/date-picker.d.ts +5 -6
  95. package/dist/types/date-range-picker.d.ts +6 -7
  96. package/dist/types/dialog.d.ts +5 -6
  97. package/dist/types/drawer.d.ts +6 -7
  98. package/dist/types/dropdown.d.ts +4 -5
  99. package/dist/types/dual-nav.d.ts +6 -7
  100. package/dist/types/empty.d.ts +4 -5
  101. package/dist/types/expression-editor.d.ts +6 -7
  102. package/dist/types/file-picker.d.ts +4 -5
  103. package/dist/types/file-viewer.d.ts +6 -7
  104. package/dist/types/float-button.d.ts +5 -6
  105. package/dist/types/form-item.d.ts +3 -4
  106. package/dist/types/form.d.ts +4 -5
  107. package/dist/types/gantt-chart.d.ts +4 -5
  108. package/dist/types/grid-input.d.ts +4 -5
  109. package/dist/types/grid.d.ts +7 -8
  110. package/dist/types/group-input.d.ts +4 -5
  111. package/dist/types/group-nav.d.ts +3 -4
  112. package/dist/types/icon.d.ts +3 -4
  113. package/dist/types/image-cropper.d.ts +9 -10
  114. package/dist/types/index.d.ts +4 -4
  115. package/dist/types/input.d.ts +4 -5
  116. package/dist/types/layout.d.ts +4 -5
  117. package/dist/types/list.d.ts +4 -5
  118. package/dist/types/loading.d.ts +5 -6
  119. package/dist/types/message-confirm.d.ts +8 -9
  120. package/dist/types/message.d.ts +8 -9
  121. package/dist/types/multi-auto-complete.d.ts +4 -5
  122. package/dist/types/multi-select.d.ts +4 -5
  123. package/dist/types/multi-tree-select.d.ts +4 -5
  124. package/dist/types/nav.d.ts +5 -6
  125. package/dist/types/node-render.d.ts +2 -3
  126. package/dist/types/notification.d.ts +8 -9
  127. package/dist/types/number-input.d.ts +3 -4
  128. package/dist/types/number-range-input.d.ts +4 -5
  129. package/dist/types/number.d.ts +3 -4
  130. package/dist/types/paginator.d.ts +4 -5
  131. package/dist/types/palette.d.ts +7 -8
  132. package/dist/types/password-input.d.ts +4 -5
  133. package/dist/types/pop-confirm.d.ts +4 -5
  134. package/dist/types/pop.d.ts +4 -5
  135. package/dist/types/progress-nodes.d.ts +4 -5
  136. package/dist/types/progress.d.ts +4 -5
  137. package/dist/types/quick-batch-edit.d.ts +4 -5
  138. package/dist/types/radio-group.d.ts +4 -5
  139. package/dist/types/radio.d.ts +4 -5
  140. package/dist/types/rich-text-editor.d.ts +6 -7
  141. package/dist/types/scroll.d.ts +5 -6
  142. package/dist/types/segment.d.ts +5 -6
  143. package/dist/types/select.d.ts +4 -5
  144. package/dist/types/slider.d.ts +4 -5
  145. package/dist/types/steps.d.ts +5 -6
  146. package/dist/types/switch.d.ts +4 -5
  147. package/dist/types/table-editor.d.ts +30 -10
  148. package/dist/types/table.d.ts +23 -13
  149. package/dist/types/tabs.d.ts +13 -14
  150. package/dist/types/tag.d.ts +3 -4
  151. package/dist/types/text-editor.d.ts +5 -6
  152. package/dist/types/text.d.ts +4 -5
  153. package/dist/types/textarea.d.ts +4 -5
  154. package/dist/types/theme.d.ts +3 -4
  155. package/dist/types/tip.d.ts +11 -8
  156. package/dist/types/tree-select.d.ts +4 -5
  157. package/dist/types/tree.d.ts +6 -6
  158. package/dist/types/watermark.d.ts +4 -5
  159. package/package.json +8 -7
  160. package/src/components/batch-edit/__test__/batch-edit.test.ts +191 -4
  161. package/src/components/batch-edit/batch-edit-form.vue +17 -3
  162. package/src/components/batch-edit/batch-edit-list.vue +2 -1
  163. package/src/components/batch-edit/batch-edit.vue +22 -4
  164. package/src/components/batch-edit/style.scss +20 -0
  165. package/src/components/batch-edit/style.ts +1 -0
  166. package/src/components/batch-edit/use-dialog-effect.ts +9 -3
  167. package/src/components/batch-edit/use-edit-state.ts +32 -4
  168. package/src/components/batch-edit/use-handlers.ts +10 -0
  169. package/src/components/batch-edit/use-shortcut-key.ts +6 -2
  170. package/src/components/file-viewer/__test__/helper.test.ts +13 -0
  171. package/src/components/file-viewer/file-viewer.vue +23 -16
  172. package/src/components/file-viewer/helper.ts +2 -0
  173. package/src/components/file-viewer/previewers/ofd-previewer.vue +216 -0
  174. package/src/components/file-viewer/style.scss +33 -0
  175. package/src/components/table/__test__/column-style.test.ts +67 -0
  176. package/src/components/table/node/col.ts +30 -1
  177. package/src/components/table/table-cell.vue +7 -2
  178. package/src/components/table/table-foot.vue +2 -0
  179. package/src/components/table/table-head.tsx +1 -0
  180. package/src/components/table/table-row.tsx +2 -0
  181. package/src/components/table-editor/__test__/table-editor.test.ts +471 -0
  182. package/src/components/table-editor/style.scss +42 -4
  183. package/src/components/table-editor/table-editor.vue +265 -38
  184. package/src/components/tip/style.scss +15 -0
  185. package/src/components/tip/tip.vue +1 -1
  186. package/src/types/batch-edit.ts +6 -0
  187. package/src/types/file-viewer.ts +1 -1
  188. package/src/types/table-editor.ts +29 -7
  189. package/src/types/table.ts +12 -0
  190. package/src/types/tip.ts +6 -1
@@ -0,0 +1,65 @@
1
+ import { OfdParseError } from "./error.js";
2
+ import { openOfdZip } from "./zip.js";
3
+ import { joinZipPath, parseDocumentRes, parseDocumentXml, parseOfdRoot, parsePageXml } from "./xml.js";
4
+ //#region ../ofd-core/dist/parse.js
5
+ /** 解析 OFD 文件字节:解包 ZIP 容器并解析全部文档的页面模型 */
6
+ async function parseOfd(data) {
7
+ return parseOfdContainer(openOfdZip(data));
8
+ }
9
+ /** 在已打开的容器上解析(复用同一个 OfdZip 读多个文档) */
10
+ async function parseOfdContainer(zip) {
11
+ if (!zip.has("OFD.xml")) throw new OfdParseError("missing-entry", "容器中缺少 OFD.xml,不是合法的 OFD 文件");
12
+ const bodies = parseOfdRoot(await zip.text("OFD.xml"));
13
+ if (bodies.length === 0) throw new OfdParseError("invalid-structure", "OFD.xml 中没有 DocBody");
14
+ return { docs: await Promise.all(bodies.map((body) => parseDoc(zip, body.docRoot, body.info))) };
15
+ }
16
+ async function parseDoc(zip, docRoot, info) {
17
+ const docLocation = joinZipPath(docRoot);
18
+ const dir = docLocation.includes("/") ? docLocation.slice(0, docLocation.lastIndexOf("/")) : "";
19
+ const documentModel = parseDocumentXml(await zip.text(docLocation), docLocation);
20
+ const [resources, pages] = await Promise.all([loadResources(zip, dir, documentModel.resLocation, documentModel.publicResLocation), Promise.all(documentModel.pageLocations.map((baseLoc, index) => loadPage(zip, dir, baseLoc, index)))]);
21
+ return {
22
+ dir,
23
+ info,
24
+ pageSize: documentModel.pageSize,
25
+ templates: documentModel.templates,
26
+ resources,
27
+ pages
28
+ };
29
+ }
30
+ /** 合并文档资源与公共资源声明;同 ID 时文档资源声明在前、查找优先 */
31
+ async function loadResources(zip, dir, resLocation, publicResLocation) {
32
+ const locations = [resLocation, publicResLocation].filter((location) => location !== null);
33
+ if (locations.length === 0) return {
34
+ fonts: [],
35
+ medias: [],
36
+ drawParams: []
37
+ };
38
+ const parts = await Promise.all(locations.map(async (location) => parseDocumentRes(await zip.text(joinZipPath(dir, location)), location)));
39
+ return {
40
+ fonts: parts.flatMap((part) => part.fonts),
41
+ medias: parts.flatMap((part) => part.medias),
42
+ drawParams: parts.flatMap((part) => part.drawParams)
43
+ };
44
+ }
45
+ async function loadPage(zip, dir, baseLoc, index) {
46
+ const pageLocation = resolveContentLocation(dir, baseLoc);
47
+ const pageModel = parsePageXml(await zip.text(pageLocation), pageLocation);
48
+ return {
49
+ index,
50
+ location: pageLocation,
51
+ size: pageModel.size,
52
+ layers: pageModel.layers
53
+ };
54
+ }
55
+ /**
56
+ * 页 / 模板页内容定位共用:BaseLoc 以 .xml 结尾时是内容文件(WPS / 数科 /
57
+ * 数电发票的页与模板页均写 Content.xml),否则按页目录处理(内含 Page.xml)。
58
+ */
59
+ function resolveContentLocation(dir, baseLoc) {
60
+ return /\.xml$/i.test(baseLoc) ? joinZipPath(dir, baseLoc) : joinZipPath(dir, baseLoc, "Page.xml");
61
+ }
62
+ //#endregion
63
+ export { joinZipPath, parseOfd, parseOfdContainer, resolveContentLocation };
64
+
65
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","names":[],"sources":["../../../../../ofd-core/dist/parse.js"],"sourcesContent":["import { OfdParseError } from \"./error.js\";\nimport { joinZipPath, parseDocumentRes, parseDocumentXml, parseOfdRoot, parsePageXml } from \"./xml.js\";\nimport { openOfdZip } from \"./zip.js\";\n//#region src/parse.ts\n/** 解析 OFD 文件字节:解包 ZIP 容器并解析全部文档的页面模型 */\nasync function parseOfd(data) {\n\treturn parseOfdContainer(openOfdZip(data));\n}\n/** 在已打开的容器上解析(复用同一个 OfdZip 读多个文档) */\nasync function parseOfdContainer(zip) {\n\tif (!zip.has(\"OFD.xml\")) throw new OfdParseError(\"missing-entry\", \"容器中缺少 OFD.xml,不是合法的 OFD 文件\");\n\tconst bodies = parseOfdRoot(await zip.text(\"OFD.xml\"));\n\tif (bodies.length === 0) throw new OfdParseError(\"invalid-structure\", \"OFD.xml 中没有 DocBody\");\n\treturn { docs: await Promise.all(bodies.map((body) => parseDoc(zip, body.docRoot, body.info))) };\n}\nasync function parseDoc(zip, docRoot, info) {\n\tconst docLocation = joinZipPath(docRoot);\n\tconst dir = docLocation.includes(\"/\") ? docLocation.slice(0, docLocation.lastIndexOf(\"/\")) : \"\";\n\tconst documentModel = parseDocumentXml(await zip.text(docLocation), docLocation);\n\tconst [resources, pages] = await Promise.all([loadResources(zip, dir, documentModel.resLocation, documentModel.publicResLocation), Promise.all(documentModel.pageLocations.map((baseLoc, index) => loadPage(zip, dir, baseLoc, index)))]);\n\treturn {\n\t\tdir,\n\t\tinfo,\n\t\tpageSize: documentModel.pageSize,\n\t\ttemplates: documentModel.templates,\n\t\tresources,\n\t\tpages\n\t};\n}\n/** 合并文档资源与公共资源声明;同 ID 时文档资源声明在前、查找优先 */\nasync function loadResources(zip, dir, resLocation, publicResLocation) {\n\tconst locations = [resLocation, publicResLocation].filter((location) => location !== null);\n\tif (locations.length === 0) return {\n\t\tfonts: [],\n\t\tmedias: [],\n\t\tdrawParams: []\n\t};\n\tconst parts = await Promise.all(locations.map(async (location) => parseDocumentRes(await zip.text(joinZipPath(dir, location)), location)));\n\treturn {\n\t\tfonts: parts.flatMap((part) => part.fonts),\n\t\tmedias: parts.flatMap((part) => part.medias),\n\t\tdrawParams: parts.flatMap((part) => part.drawParams)\n\t};\n}\nasync function loadPage(zip, dir, baseLoc, index) {\n\tconst pageLocation = resolveContentLocation(dir, baseLoc);\n\tconst pageModel = parsePageXml(await zip.text(pageLocation), pageLocation);\n\treturn {\n\t\tindex,\n\t\tlocation: pageLocation,\n\t\tsize: pageModel.size,\n\t\tlayers: pageModel.layers\n\t};\n}\n/**\n* 页 / 模板页内容定位共用:BaseLoc 以 .xml 结尾时是内容文件(WPS / 数科 /\n* 数电发票的页与模板页均写 Content.xml),否则按页目录处理(内含 Page.xml)。\n*/\nfunction resolveContentLocation(dir, baseLoc) {\n\treturn /\\.xml$/i.test(baseLoc) ? joinZipPath(dir, baseLoc) : joinZipPath(dir, baseLoc, \"Page.xml\");\n}\n//#endregion\nexport { joinZipPath, parseOfd, parseOfdContainer, resolveContentLocation };\n\n//# sourceMappingURL=parse.js.map"],"mappings":";;;;;AAKA,eAAe,SAAS,MAAM;CAC7B,OAAO,kBAAkB,WAAW,IAAI,CAAC;AAC1C;;AAEA,eAAe,kBAAkB,KAAK;CACrC,IAAI,CAAC,IAAI,IAAI,SAAS,GAAG,MAAM,IAAI,cAAc,iBAAiB,4BAA4B;CAC9F,MAAM,SAAS,aAAa,MAAM,IAAI,KAAK,SAAS,CAAC;CACrD,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,cAAc,qBAAqB,qBAAqB;CAC3F,OAAO,EAAE,MAAM,MAAM,QAAQ,IAAI,OAAO,KAAK,SAAS,SAAS,KAAK,KAAK,SAAS,KAAK,IAAI,CAAC,CAAC,EAAE;AAChG;AACA,eAAe,SAAS,KAAK,SAAS,MAAM;CAC3C,MAAM,cAAc,YAAY,OAAO;CACvC,MAAM,MAAM,YAAY,SAAS,GAAG,IAAI,YAAY,MAAM,GAAG,YAAY,YAAY,GAAG,CAAC,IAAI;CAC7F,MAAM,gBAAgB,iBAAiB,MAAM,IAAI,KAAK,WAAW,GAAG,WAAW;CAC/E,MAAM,CAAC,WAAW,SAAS,MAAM,QAAQ,IAAI,CAAC,cAAc,KAAK,KAAK,cAAc,aAAa,cAAc,iBAAiB,GAAG,QAAQ,IAAI,cAAc,cAAc,KAAK,SAAS,UAAU,SAAS,KAAK,KAAK,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC;CACxO,OAAO;EACN;EACA;EACA,UAAU,cAAc;EACxB,WAAW,cAAc;EACzB;EACA;CACD;AACD;;AAEA,eAAe,cAAc,KAAK,KAAK,aAAa,mBAAmB;CACtE,MAAM,YAAY,CAAC,aAAa,iBAAiB,CAAC,CAAC,QAAQ,aAAa,aAAa,IAAI;CACzF,IAAI,UAAU,WAAW,GAAG,OAAO;EAClC,OAAO,CAAC;EACR,QAAQ,CAAC;EACT,YAAY,CAAC;CACd;CACA,MAAM,QAAQ,MAAM,QAAQ,IAAI,UAAU,IAAI,OAAO,aAAa,iBAAiB,MAAM,IAAI,KAAK,YAAY,KAAK,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;CACzI,OAAO;EACN,OAAO,MAAM,SAAS,SAAS,KAAK,KAAK;EACzC,QAAQ,MAAM,SAAS,SAAS,KAAK,MAAM;EAC3C,YAAY,MAAM,SAAS,SAAS,KAAK,UAAU;CACpD;AACD;AACA,eAAe,SAAS,KAAK,KAAK,SAAS,OAAO;CACjD,MAAM,eAAe,uBAAuB,KAAK,OAAO;CACxD,MAAM,YAAY,aAAa,MAAM,IAAI,KAAK,YAAY,GAAG,YAAY;CACzE,OAAO;EACN;EACA,UAAU;EACV,MAAM,UAAU;EAChB,QAAQ,UAAU;CACnB;AACD;;;;;AAKA,SAAS,uBAAuB,KAAK,SAAS;CAC7C,OAAO,UAAU,KAAK,OAAO,IAAI,YAAY,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,UAAU;AAClG"}
@@ -0,0 +1,361 @@
1
+ import { OfdParseError } from "./error.js";
2
+ import { IDENTITY_MATRIX, multiplyMatrix } from "./ctm.js";
3
+ import { joinZipPath } from "./xml.js";
4
+ import { resolveContentLocation } from "./parse.js";
5
+ import { formatNumber, roundTo } from "./number.js";
6
+ import { glyphPathD, parseEmbeddedFont } from "./font.js";
7
+ import { parsePageContent } from "./page-objects.js";
8
+ //#region ../ofd-core/dist/render.js
9
+ /**
10
+ * 逐页 SVG 输出(P2 渲染内核出口)。
11
+ *
12
+ * 页面物理尺寸按 OFD 毫米 → CSS 像素换算(96dpi),内容坐标系保持 OFD 原始
13
+ * 毫米单位(通过 viewBox 缩放),坐标与文档声明一一对应,便于断言与调试。
14
+ * 页与页相互独立、可单独调用,供上层做懒渲染 / 虚拟滚动。
15
+ */
16
+ /** CSS 约定 96px = 1in = 25.4mm */
17
+ const PX_PER_MM = 96 / 25.4;
18
+ /** 对象未声明填充色时的默认色(GB/T 33190 未声明时文字按黑色呈现,Fill 路径同) */
19
+ const DEFAULT_FILL = "#000";
20
+ /** 输出指定文档指定页的完整 SVG 字符串 */
21
+ async function pageToSvg(zip, container, documentIndex, pageIndex) {
22
+ const doc = container.docs[documentIndex];
23
+ if (!doc) throw new OfdParseError("out-of-range", `文档序号 ${documentIndex} 超出范围(容器共 ${container.docs.length} 个文档)`);
24
+ const page = doc.pages[pageIndex];
25
+ if (!page) throw new OfdParseError("out-of-range", `页序号 ${pageIndex} 超出范围(文档 ${documentIndex} 共 ${doc.pages.length} 页)`);
26
+ const content = parsePageContent(await zip.text(page.location), page.location);
27
+ const size = page.size ?? doc.pageSize ?? {
28
+ width: 210,
29
+ height: 297
30
+ };
31
+ const context = {
32
+ zip,
33
+ doc,
34
+ fonts: /* @__PURE__ */ new Map(),
35
+ templateContents: /* @__PURE__ */ new Map()
36
+ };
37
+ const renderedTemplates = await Promise.all(content.templateRefs.map((ref) => renderTemplateRef(ref, context, [content.objectsById], /* @__PURE__ */ new Set())));
38
+ const background = [];
39
+ const foreground = [];
40
+ const templateFrames = [];
41
+ for (const rendered of renderedTemplates) {
42
+ if (rendered.background !== "") background.push(rendered.background);
43
+ if (rendered.foreground !== "") foreground.push(rendered.foreground);
44
+ templateFrames.push(rendered.frames);
45
+ }
46
+ const pageFrames = [content.objectsById, ...templateFrames.flat()];
47
+ const layers = await Promise.all(content.layers.map((layer) => renderLayer(layer, context, pageFrames)));
48
+ return `<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${formatNumber(roundTo(size.width * PX_PER_MM, 2))}px" height="${formatNumber(roundTo(size.height * PX_PER_MM, 2))}px" viewBox="0 0 ${formatNumber(size.width)} ${formatNumber(size.height)}">${background.join("")}${layers.join("")}${foreground.join("")}</svg>`;
49
+ }
50
+ /** 渲染单个图层:对象按声明顺序叠加,空图层不输出外壳 */
51
+ async function renderLayer(layer, context, frames) {
52
+ const rendered = (await Promise.all(layer.objects.map((object) => renderObject(object, IDENTITY_MATRIX, null, context, /* @__PURE__ */ new Set(), {
53
+ frames,
54
+ drawParamId: layer.drawParamId
55
+ })))).join("");
56
+ if (rendered === "") return "";
57
+ return `<g${layer.type === null ? "" : ` data-ofd-layer="${layer.type}"`}>${rendered}</g>`;
58
+ }
59
+ /**
60
+ * 按引用渲染一个模板页:自身引用的模板先于其内容(背景)或后于其内容(前景)
61
+ * 展开,与页面同规则;以内容文件路径判环,递归引用直接断开。
62
+ */
63
+ async function renderTemplateRef(ref, context, outerFrames, visiting) {
64
+ const baseLocation = (ref.templateId === null ? void 0 : context.doc.templates.find((template) => template.id === ref.templateId))?.location ?? null;
65
+ if (baseLocation === null) return {
66
+ background: "",
67
+ foreground: "",
68
+ frames: []
69
+ };
70
+ const location = resolveContentLocation(context.doc.dir, baseLocation);
71
+ if (visiting.has(location)) return {
72
+ background: "",
73
+ foreground: "",
74
+ frames: []
75
+ };
76
+ const content = await loadTemplateContent(context, location);
77
+ const frames = [content.objectsById, ...outerFrames];
78
+ const nextVisiting = new Set(visiting).add(location);
79
+ const innerRendered = await Promise.all(content.templateRefs.map((innerRef) => renderTemplateRef(innerRef, context, frames, nextVisiting)));
80
+ const innerBackground = [];
81
+ const innerForeground = [];
82
+ for (const rendered of innerRendered) {
83
+ innerBackground.push(rendered.background);
84
+ innerForeground.push(rendered.foreground);
85
+ }
86
+ const ownLayers = (await Promise.all(content.layers.map((layer) => renderLayer(layer, context, frames)))).join("");
87
+ const bundle = innerBackground.join("") + ownLayers + innerForeground.join("");
88
+ return ref.zOrder === "foreground" ? {
89
+ background: "",
90
+ foreground: bundle,
91
+ frames
92
+ } : {
93
+ background: bundle,
94
+ foreground: "",
95
+ frames
96
+ };
97
+ }
98
+ /** 加载并解析模板页内容;同一页内重复或递归引用复用解析结果 */
99
+ async function loadTemplateContent(context, location) {
100
+ const cached = context.templateContents.get(location);
101
+ if (cached) return cached;
102
+ const content = parsePageContent(await context.zip.text(location), location);
103
+ context.templateContents.set(location, content);
104
+ return content;
105
+ }
106
+ /** 渲染单个对象:CTM 链 + Boundary 定位外壳,内容坐标相对 Boundary 原点 */
107
+ async function renderObject(object, parentCtm, boundaryOverride, context, visiting, scope) {
108
+ if (object.id && visiting.has(object.id)) return "";
109
+ const ctm = object.ctm ? multiplyMatrix(parentCtm, object.ctm) : parentCtm;
110
+ if (object.kind === "composite") return renderComposite(object, ctm, context, visiting, scope);
111
+ const boundary = boundaryOverride ?? object.boundary;
112
+ const inner = await renderContent(object, boundary, ctm, context, scope);
113
+ if (inner === "") return "";
114
+ const transform = groupTransform(ctm, boundary);
115
+ return `<g${transform ? ` transform="${transform}"` : ""}>${inner}</g>`;
116
+ }
117
+ async function renderContent(object, boundary, ctm, context, scope) {
118
+ switch (object.kind) {
119
+ case "text": return renderText(object, context, scope);
120
+ case "image": return renderImage(object, boundary, ctm, context);
121
+ case "path": return renderPath(object, context, scope);
122
+ }
123
+ }
124
+ /** 复合对象:递归渲染被引用对象,CTM 链向下继承,循环引用直接断开 */
125
+ async function renderComposite(object, parentCtm, context, visiting, scope) {
126
+ const referenced = findReferencedObject(object, scope);
127
+ if (!referenced) return "";
128
+ const nextVisiting = new Set(visiting);
129
+ if (object.id) nextVisiting.add(object.id);
130
+ return renderObject(referenced, parentCtm, object.boundary, context, nextVisiting, scope);
131
+ }
132
+ /** 复合对象引用查找:当前内容域优先,未命中再沿外层内容域兜底 */
133
+ function findReferencedObject(object, scope) {
134
+ if (object.referenceId === null) return void 0;
135
+ for (const frame of scope.frames) {
136
+ const referenced = frame.get(object.referenceId);
137
+ if (referenced) return referenced;
138
+ }
139
+ }
140
+ /** 文本渲染:声明内嵌字体(Font@FontFile)时按 glyph 轮廓输出 path,否则回退系统字体 text */
141
+ async function renderText(object, context, scope) {
142
+ const draw = resolveDrawAttributes(object.drawParamId ?? scope.drawParamId, context);
143
+ const fill = object.fillColor ?? draw.fillColor ?? DEFAULT_FILL;
144
+ const font = await loadEmbeddedFont(object.fontId, context);
145
+ if (!font || object.fontSize === null) return renderSystemFontText(object, fill, context);
146
+ const fontSize = object.fontSize;
147
+ const parts = [];
148
+ let baseIndex = 0;
149
+ for (const code of object.codes) {
150
+ const part = textCodePathD(font, code, fontSize, object.glyphSubstitutions, baseIndex);
151
+ if (part !== "") parts.push(part);
152
+ baseIndex += code.text.length;
153
+ }
154
+ const d = parts.join(" ");
155
+ if (d === "") return object.codes.some((code) => code.text.length > 0) ? renderSystemFontText(object, fill, context) : "";
156
+ return `<path d="${d}" fill="${fill}"/>`;
157
+ }
158
+ /** 加载 TextObject@FontID 声明的内嵌 TTF;缺失或损坏返回 null(不阻断整页渲染) */
159
+ async function loadEmbeddedFont(fontId, context) {
160
+ if (fontId === null) return null;
161
+ const cached = context.fonts.get(fontId);
162
+ if (cached !== void 0) return cached;
163
+ const decl = context.doc.resources.fonts.find((font) => font.id === fontId);
164
+ let font = null;
165
+ if (decl?.fontFile) try {
166
+ font = parseEmbeddedFont(await context.zip.read(joinZipPath(context.doc.dir, decl.fontFile)), decl.fontFile);
167
+ } catch {
168
+ font = null;
169
+ }
170
+ context.fonts.set(fontId, font);
171
+ return font;
172
+ }
173
+ /**
174
+ * 单个 TextCode 的 glyph 路径:从 X/Y 基线原点起笔逐字排布。
175
+ * DeltaX/DeltaY 按标准是「相对前一个字符的位移」,声明时替代字形步进宽度。
176
+ * 字形来源优先取 CGTransform 替换序号(子集字体无 cmap 时的唯一映射),
177
+ * 其次 cmap 码点映射;两者都未命中时跳过该字符的轮廓、仅按位移推进。
178
+ */
179
+ function textCodePathD(font, code, fontSize, substitutions, baseIndex) {
180
+ const scale = fontSize / font.unitsPerEm;
181
+ const parts = [];
182
+ let penX = code.x ?? 0;
183
+ let penY = code.y ?? 0;
184
+ let dxIndex = 0;
185
+ let dyIndex = 0;
186
+ let charIndex = 0;
187
+ for (const char of code.text) {
188
+ const gid = substitutedGlyphId(substitutions, baseIndex + charIndex) ?? font.glyphIndexOf(char.codePointAt(0));
189
+ if (gid !== null) {
190
+ const d = glyphPathD(font, gid, fontSize, penX, penY);
191
+ if (d !== "") parts.push(d);
192
+ }
193
+ const deltaX = dxIndex < code.deltaX.length ? code.deltaX[dxIndex++] : null;
194
+ penX += deltaX ?? (gid !== null ? font.advanceWidth(gid) * scale : 0);
195
+ const deltaY = dyIndex < code.deltaY.length ? code.deltaY[dyIndex++] : null;
196
+ penY += deltaY ?? 0;
197
+ charIndex++;
198
+ }
199
+ return parts.join(" ");
200
+ }
201
+ /** 字形替换查找:字符落在声明区间时取 Glyphs 中对应序号,合字耗尽或未覆盖返回 null */
202
+ function substitutedGlyphId(substitutions, charIndex) {
203
+ for (const substitution of substitutions) if (charIndex >= substitution.codePosition && charIndex < substitution.codePosition + substitution.codeCount) {
204
+ const offset = charIndex - substitution.codePosition;
205
+ return offset < substitution.glyphIds.length ? substitution.glyphIds[offset] : null;
206
+ }
207
+ return null;
208
+ }
209
+ /** 无内嵌字体可用时的系统字体回退:保留 P2 的 text 输出与文字内容 */
210
+ function renderSystemFontText(object, fill, context) {
211
+ const fontFamily = resolveFontFamily(object.fontId, context);
212
+ return object.codes.map((code) => {
213
+ return `<text ${[
214
+ "xml:space=\"preserve\"",
215
+ codePositionAttr("x", code.x, code.text.length, code.deltaX),
216
+ codePositionAttr("y", code.y, code.text.length, code.deltaY),
217
+ attr("font-size", object.fontSize),
218
+ fontFamily === null ? null : `font-family="${escapeXml(fontFamily)}"`,
219
+ `fill="${fill}"`
220
+ ].filter((value) => value !== null).join(" ")}>${escapeXml(code.text)}</text>`;
221
+ }).join("");
222
+ }
223
+ /**
224
+ * TextCode 位移转 SVG 逐字符坐标:DeltaX/DeltaY 是相邻字符间的绝对步长
225
+ * (替代字形自然步进),而 SVG 的 dx/dy 是在自然步进上的附加量,语义不同,
226
+ * 这里换算成绝对坐标列表;位移未覆盖的字符交由自然排布。
227
+ */
228
+ function codePositionAttr(name, start, charCount, deltas) {
229
+ if (start === null && deltas.length === 0) return null;
230
+ const positions = [start ?? 0];
231
+ const covered = Math.min(charCount - 1, deltas.length);
232
+ for (let index = 0; index < covered; index++) positions.push(positions[index] + deltas[index]);
233
+ return positions.length === 1 ? `${name}="${formatNumber(positions[0])}"` : `${name}="${positions.map(formatNumber).join(" ")}"`;
234
+ }
235
+ function resolveFontFamily(fontId, context) {
236
+ if (!fontId) return null;
237
+ return context.doc.resources.fonts.find((font) => font.id === fontId)?.fontName ?? null;
238
+ }
239
+ /**
240
+ * 图片:解析 MultiMedia 声明并读资源字节,缺资源或不可识别的媒体类型跳过(不阻断整页)。
241
+ * Type 兼容标准单字母 'g' 与主流产出的 'Image' 拼写。
242
+ */
243
+ async function renderImage(object, boundary, ctm, context) {
244
+ const media = object.resourceId === null ? void 0 : context.doc.resources.medias.find((item) => item.id === object.resourceId);
245
+ const location = media?.location;
246
+ const type = media?.type?.toLowerCase();
247
+ if (!location || type !== void 0 && type !== "g" && type !== "image") return "";
248
+ let bytes;
249
+ try {
250
+ bytes = await context.zip.read(joinZipPath(context.doc.dir, location));
251
+ } catch {
252
+ return "";
253
+ }
254
+ const mime = sniffImageMime(bytes);
255
+ if (!mime) return "";
256
+ const content = boundary === null ? null : imageContentSize(boundary, ctm);
257
+ return `<image${content === null ? "" : ` width="${formatNumber(content.width)}" height="${formatNumber(content.height)}"`} href="data:${mime};base64,${toBase64(bytes)}"/>`;
258
+ }
259
+ /**
260
+ * 图片内容盒尺寸:无缩放 CTM 时 Boundary 即内容盒;带缩放 CTM 的产出
261
+ * (WPS / 新版数电发票实证)图片内容为 [0,1] 单位盒,尺寸与定位由 CTM 给出,
262
+ * Boundary 只提供平移原点(WPS 写最终包围盒、数电票二维码写整页盒,均不参与定尺寸)。
263
+ */
264
+ function imageContentSize(boundary, ctm) {
265
+ if (!hasScaleComponent(ctm)) return {
266
+ width: boundary.width,
267
+ height: boundary.height
268
+ };
269
+ return {
270
+ width: 1,
271
+ height: 1
272
+ };
273
+ }
274
+ /** 按魔数识别可渲染的图片媒体类型;多帧格式(GIF/APNG)由展示端取首帧 */
275
+ function sniffImageMime(bytes) {
276
+ if (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return "image/png";
277
+ if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
278
+ if (bytes.length >= 3 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) return "image/gif";
279
+ if (bytes.length >= 2 && bytes[0] === 66 && bytes[1] === 77) return "image/bmp";
280
+ if (bytes.length >= 12 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) return "image/webp";
281
+ return null;
282
+ }
283
+ function toBase64(bytes) {
284
+ let binary = "";
285
+ const chunkSize = 32768;
286
+ for (let offset = 0; offset < bytes.length; offset += chunkSize) binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
287
+ return btoa(binary);
288
+ }
289
+ /** 对象生效绘制参数:自身 FillColor/StrokeColor/LineWidth 声明优先于 DrawParam 继承链 */
290
+ function resolveDrawAttributes(drawParamId, context) {
291
+ const chain = [];
292
+ const visited = /* @__PURE__ */ new Set();
293
+ let current = drawParamId === null ? void 0 : findDrawParam(drawParamId, context);
294
+ while (current && !visited.has(current.id)) {
295
+ visited.add(current.id);
296
+ chain.unshift(current);
297
+ current = current.relative === null ? void 0 : findDrawParam(current.relative, context);
298
+ }
299
+ let fillColor = null;
300
+ let strokeColor = null;
301
+ let lineWidth = null;
302
+ for (const declaration of chain) {
303
+ fillColor ??= declaration.fillColor;
304
+ strokeColor ??= declaration.strokeColor;
305
+ lineWidth ??= declaration.lineWidth;
306
+ }
307
+ return {
308
+ fillColor,
309
+ strokeColor,
310
+ lineWidth
311
+ };
312
+ }
313
+ function findDrawParam(id, context) {
314
+ return context.doc.resources.drawParams.find((param) => param.id === id);
315
+ }
316
+ function renderPath(object, context, scope) {
317
+ const d = pathD(object.commands);
318
+ if (d === "") return "";
319
+ const draw = resolveDrawAttributes(object.drawParamId ?? scope.drawParamId, context);
320
+ const strokeColor = object.strokeColor ?? draw.strokeColor;
321
+ const fill = object.fillColor ?? draw.fillColor ?? (object.fill ? DEFAULT_FILL : "none");
322
+ return `<path ${[
323
+ `d="${d}"`,
324
+ `fill="${fill}"`,
325
+ strokeColor === null ? null : `stroke="${strokeColor}"`,
326
+ attr("stroke-width", object.lineWidth ?? draw.lineWidth),
327
+ listAttr("stroke-dasharray", object.dashPattern)
328
+ ].filter((value) => value !== null).join(" ")}/>`;
329
+ }
330
+ function pathD(commands) {
331
+ return commands.map((command) => command.type === "Z" ? "Z" : `${command.type === "B" ? "Q" : command.type} ${command.points.map(formatNumber).join(" ")}`).join(" ");
332
+ }
333
+ /** 对象外壳 transform:CTM 矩阵 + 平移到 Boundary 原点,单位矩阵不输出 */
334
+ function groupTransform(ctm, boundary) {
335
+ const matrix = isIdentityMatrix(ctm) ? null : `matrix(${ctm.map(formatNumber).join(" ")})`;
336
+ if (!boundary) return matrix ?? "";
337
+ const translate = `translate(${formatNumber(boundary.x)} ${formatNumber(boundary.y)})`;
338
+ if (hasScaleComponent(ctm)) return matrix ? `${translate} ${matrix}` : translate;
339
+ return matrix ? `${matrix} ${translate}` : translate;
340
+ }
341
+ /** CTM 是否带缩放分量(旋转/切变的轴长为 1,缩放会偏离 1) */
342
+ function hasScaleComponent(ctm) {
343
+ return Math.abs(Math.hypot(ctm[0], ctm[1]) - 1) > 1e-6 || Math.abs(Math.hypot(ctm[2], ctm[3]) - 1) > 1e-6;
344
+ }
345
+ function isIdentityMatrix(matrix) {
346
+ return matrix[0] === 1 && matrix[1] === 0 && matrix[2] === 0 && matrix[3] === 1 && matrix[4] === 0 && matrix[5] === 0;
347
+ }
348
+ function attr(name, value) {
349
+ if (value === null) return null;
350
+ return `${name}="${typeof value === "number" ? formatNumber(value) : escapeXml(value)}"`;
351
+ }
352
+ function listAttr(name, values) {
353
+ return values.length === 0 ? null : `${name}="${values.map(formatNumber).join(" ")}"`;
354
+ }
355
+ function escapeXml(text) {
356
+ return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
357
+ }
358
+ //#endregion
359
+ export { pageToSvg };
360
+
361
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","names":[],"sources":["../../../../../ofd-core/dist/render.js"],"sourcesContent":["import { OfdParseError } from \"./error.js\";\nimport { IDENTITY_MATRIX, multiplyMatrix } from \"./ctm.js\";\nimport { joinZipPath } from \"./xml.js\";\nimport { resolveContentLocation } from \"./parse.js\";\nimport { formatNumber, roundTo } from \"./number.js\";\nimport { glyphPathD, parseEmbeddedFont } from \"./font.js\";\nimport { parsePageContent } from \"./page-objects.js\";\n//#region src/render.ts\n/**\n* 逐页 SVG 输出(P2 渲染内核出口)。\n*\n* 页面物理尺寸按 OFD 毫米 → CSS 像素换算(96dpi),内容坐标系保持 OFD 原始\n* 毫米单位(通过 viewBox 缩放),坐标与文档声明一一对应,便于断言与调试。\n* 页与页相互独立、可单独调用,供上层做懒渲染 / 虚拟滚动。\n*/\n/** CSS 约定 96px = 1in = 25.4mm */\nconst PX_PER_MM = 96 / 25.4;\n/** 对象未声明填充色时的默认色(GB/T 33190 未声明时文字按黑色呈现,Fill 路径同) */\nconst DEFAULT_FILL = \"#000\";\n/** 输出指定文档指定页的完整 SVG 字符串 */\nasync function pageToSvg(zip, container, documentIndex, pageIndex) {\n\tconst doc = container.docs[documentIndex];\n\tif (!doc) throw new OfdParseError(\"out-of-range\", `文档序号 ${documentIndex} 超出范围(容器共 ${container.docs.length} 个文档)`);\n\tconst page = doc.pages[pageIndex];\n\tif (!page) throw new OfdParseError(\"out-of-range\", `页序号 ${pageIndex} 超出范围(文档 ${documentIndex} 共 ${doc.pages.length} 页)`);\n\tconst content = parsePageContent(await zip.text(page.location), page.location);\n\tconst size = page.size ?? doc.pageSize ?? {\n\t\twidth: 210,\n\t\theight: 297\n\t};\n\tconst context = {\n\t\tzip,\n\t\tdoc,\n\t\tfonts: /* @__PURE__ */ new Map(),\n\t\ttemplateContents: /* @__PURE__ */ new Map()\n\t};\n\tconst renderedTemplates = await Promise.all(content.templateRefs.map((ref) => renderTemplateRef(ref, context, [content.objectsById], /* @__PURE__ */ new Set())));\n\tconst background = [];\n\tconst foreground = [];\n\tconst templateFrames = [];\n\tfor (const rendered of renderedTemplates) {\n\t\tif (rendered.background !== \"\") background.push(rendered.background);\n\t\tif (rendered.foreground !== \"\") foreground.push(rendered.foreground);\n\t\ttemplateFrames.push(rendered.frames);\n\t}\n\tconst pageFrames = [content.objectsById, ...templateFrames.flat()];\n\tconst layers = await Promise.all(content.layers.map((layer) => renderLayer(layer, context, pageFrames)));\n\treturn `<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"${formatNumber(roundTo(size.width * PX_PER_MM, 2))}px\" height=\"${formatNumber(roundTo(size.height * PX_PER_MM, 2))}px\" viewBox=\"0 0 ${formatNumber(size.width)} ${formatNumber(size.height)}\">${background.join(\"\")}${layers.join(\"\")}${foreground.join(\"\")}</svg>`;\n}\n/** 渲染单个图层:对象按声明顺序叠加,空图层不输出外壳 */\nasync function renderLayer(layer, context, frames) {\n\tconst rendered = (await Promise.all(layer.objects.map((object) => renderObject(object, IDENTITY_MATRIX, null, context, /* @__PURE__ */ new Set(), {\n\t\tframes,\n\t\tdrawParamId: layer.drawParamId\n\t})))).join(\"\");\n\tif (rendered === \"\") return \"\";\n\treturn `<g${layer.type === null ? \"\" : ` data-ofd-layer=\"${layer.type}\"`}>${rendered}</g>`;\n}\n/**\n* 按引用渲染一个模板页:自身引用的模板先于其内容(背景)或后于其内容(前景)\n* 展开,与页面同规则;以内容文件路径判环,递归引用直接断开。\n*/\nasync function renderTemplateRef(ref, context, outerFrames, visiting) {\n\tconst baseLocation = (ref.templateId === null ? void 0 : context.doc.templates.find((template) => template.id === ref.templateId))?.location ?? null;\n\tif (baseLocation === null) return {\n\t\tbackground: \"\",\n\t\tforeground: \"\",\n\t\tframes: []\n\t};\n\tconst location = resolveContentLocation(context.doc.dir, baseLocation);\n\tif (visiting.has(location)) return {\n\t\tbackground: \"\",\n\t\tforeground: \"\",\n\t\tframes: []\n\t};\n\tconst content = await loadTemplateContent(context, location);\n\tconst frames = [content.objectsById, ...outerFrames];\n\tconst nextVisiting = new Set(visiting).add(location);\n\tconst innerRendered = await Promise.all(content.templateRefs.map((innerRef) => renderTemplateRef(innerRef, context, frames, nextVisiting)));\n\tconst innerBackground = [];\n\tconst innerForeground = [];\n\tfor (const rendered of innerRendered) {\n\t\tinnerBackground.push(rendered.background);\n\t\tinnerForeground.push(rendered.foreground);\n\t}\n\tconst ownLayers = (await Promise.all(content.layers.map((layer) => renderLayer(layer, context, frames)))).join(\"\");\n\tconst bundle = innerBackground.join(\"\") + ownLayers + innerForeground.join(\"\");\n\treturn ref.zOrder === \"foreground\" ? {\n\t\tbackground: \"\",\n\t\tforeground: bundle,\n\t\tframes\n\t} : {\n\t\tbackground: bundle,\n\t\tforeground: \"\",\n\t\tframes\n\t};\n}\n/** 加载并解析模板页内容;同一页内重复或递归引用复用解析结果 */\nasync function loadTemplateContent(context, location) {\n\tconst cached = context.templateContents.get(location);\n\tif (cached) return cached;\n\tconst content = parsePageContent(await context.zip.text(location), location);\n\tcontext.templateContents.set(location, content);\n\treturn content;\n}\n/** 渲染单个对象:CTM 链 + Boundary 定位外壳,内容坐标相对 Boundary 原点 */\nasync function renderObject(object, parentCtm, boundaryOverride, context, visiting, scope) {\n\tif (object.id && visiting.has(object.id)) return \"\";\n\tconst ctm = object.ctm ? multiplyMatrix(parentCtm, object.ctm) : parentCtm;\n\tif (object.kind === \"composite\") return renderComposite(object, ctm, context, visiting, scope);\n\tconst boundary = boundaryOverride ?? object.boundary;\n\tconst inner = await renderContent(object, boundary, ctm, context, scope);\n\tif (inner === \"\") return \"\";\n\tconst transform = groupTransform(ctm, boundary);\n\treturn `<g${transform ? ` transform=\"${transform}\"` : \"\"}>${inner}</g>`;\n}\nasync function renderContent(object, boundary, ctm, context, scope) {\n\tswitch (object.kind) {\n\t\tcase \"text\": return renderText(object, context, scope);\n\t\tcase \"image\": return renderImage(object, boundary, ctm, context);\n\t\tcase \"path\": return renderPath(object, context, scope);\n\t}\n}\n/** 复合对象:递归渲染被引用对象,CTM 链向下继承,循环引用直接断开 */\nasync function renderComposite(object, parentCtm, context, visiting, scope) {\n\tconst referenced = findReferencedObject(object, scope);\n\tif (!referenced) return \"\";\n\tconst nextVisiting = new Set(visiting);\n\tif (object.id) nextVisiting.add(object.id);\n\treturn renderObject(referenced, parentCtm, object.boundary, context, nextVisiting, scope);\n}\n/** 复合对象引用查找:当前内容域优先,未命中再沿外层内容域兜底 */\nfunction findReferencedObject(object, scope) {\n\tif (object.referenceId === null) return void 0;\n\tfor (const frame of scope.frames) {\n\t\tconst referenced = frame.get(object.referenceId);\n\t\tif (referenced) return referenced;\n\t}\n}\n/** 文本渲染:声明内嵌字体(Font@FontFile)时按 glyph 轮廓输出 path,否则回退系统字体 text */\nasync function renderText(object, context, scope) {\n\tconst draw = resolveDrawAttributes(object.drawParamId ?? scope.drawParamId, context);\n\tconst fill = object.fillColor ?? draw.fillColor ?? DEFAULT_FILL;\n\tconst font = await loadEmbeddedFont(object.fontId, context);\n\tif (!font || object.fontSize === null) return renderSystemFontText(object, fill, context);\n\tconst fontSize = object.fontSize;\n\tconst parts = [];\n\tlet baseIndex = 0;\n\tfor (const code of object.codes) {\n\t\tconst part = textCodePathD(font, code, fontSize, object.glyphSubstitutions, baseIndex);\n\t\tif (part !== \"\") parts.push(part);\n\t\tbaseIndex += code.text.length;\n\t}\n\tconst d = parts.join(\" \");\n\tif (d === \"\") return object.codes.some((code) => code.text.length > 0) ? renderSystemFontText(object, fill, context) : \"\";\n\treturn `<path d=\"${d}\" fill=\"${fill}\"/>`;\n}\n/** 加载 TextObject@FontID 声明的内嵌 TTF;缺失或损坏返回 null(不阻断整页渲染) */\nasync function loadEmbeddedFont(fontId, context) {\n\tif (fontId === null) return null;\n\tconst cached = context.fonts.get(fontId);\n\tif (cached !== void 0) return cached;\n\tconst decl = context.doc.resources.fonts.find((font) => font.id === fontId);\n\tlet font = null;\n\tif (decl?.fontFile) try {\n\t\tfont = parseEmbeddedFont(await context.zip.read(joinZipPath(context.doc.dir, decl.fontFile)), decl.fontFile);\n\t} catch {\n\t\tfont = null;\n\t}\n\tcontext.fonts.set(fontId, font);\n\treturn font;\n}\n/**\n* 单个 TextCode 的 glyph 路径:从 X/Y 基线原点起笔逐字排布。\n* DeltaX/DeltaY 按标准是「相对前一个字符的位移」,声明时替代字形步进宽度。\n* 字形来源优先取 CGTransform 替换序号(子集字体无 cmap 时的唯一映射),\n* 其次 cmap 码点映射;两者都未命中时跳过该字符的轮廓、仅按位移推进。\n*/\nfunction textCodePathD(font, code, fontSize, substitutions, baseIndex) {\n\tconst scale = fontSize / font.unitsPerEm;\n\tconst parts = [];\n\tlet penX = code.x ?? 0;\n\tlet penY = code.y ?? 0;\n\tlet dxIndex = 0;\n\tlet dyIndex = 0;\n\tlet charIndex = 0;\n\tfor (const char of code.text) {\n\t\tconst gid = substitutedGlyphId(substitutions, baseIndex + charIndex) ?? font.glyphIndexOf(char.codePointAt(0));\n\t\tif (gid !== null) {\n\t\t\tconst d = glyphPathD(font, gid, fontSize, penX, penY);\n\t\t\tif (d !== \"\") parts.push(d);\n\t\t}\n\t\tconst deltaX = dxIndex < code.deltaX.length ? code.deltaX[dxIndex++] : null;\n\t\tpenX += deltaX ?? (gid !== null ? font.advanceWidth(gid) * scale : 0);\n\t\tconst deltaY = dyIndex < code.deltaY.length ? code.deltaY[dyIndex++] : null;\n\t\tpenY += deltaY ?? 0;\n\t\tcharIndex++;\n\t}\n\treturn parts.join(\" \");\n}\n/** 字形替换查找:字符落在声明区间时取 Glyphs 中对应序号,合字耗尽或未覆盖返回 null */\nfunction substitutedGlyphId(substitutions, charIndex) {\n\tfor (const substitution of substitutions) if (charIndex >= substitution.codePosition && charIndex < substitution.codePosition + substitution.codeCount) {\n\t\tconst offset = charIndex - substitution.codePosition;\n\t\treturn offset < substitution.glyphIds.length ? substitution.glyphIds[offset] : null;\n\t}\n\treturn null;\n}\n/** 无内嵌字体可用时的系统字体回退:保留 P2 的 text 输出与文字内容 */\nfunction renderSystemFontText(object, fill, context) {\n\tconst fontFamily = resolveFontFamily(object.fontId, context);\n\treturn object.codes.map((code) => {\n\t\treturn `<text ${[\n\t\t\t\"xml:space=\\\"preserve\\\"\",\n\t\t\tcodePositionAttr(\"x\", code.x, code.text.length, code.deltaX),\n\t\t\tcodePositionAttr(\"y\", code.y, code.text.length, code.deltaY),\n\t\t\tattr(\"font-size\", object.fontSize),\n\t\t\tfontFamily === null ? null : `font-family=\"${escapeXml(fontFamily)}\"`,\n\t\t\t`fill=\"${fill}\"`\n\t\t].filter((value) => value !== null).join(\" \")}>${escapeXml(code.text)}</text>`;\n\t}).join(\"\");\n}\n/**\n* TextCode 位移转 SVG 逐字符坐标:DeltaX/DeltaY 是相邻字符间的绝对步长\n* (替代字形自然步进),而 SVG 的 dx/dy 是在自然步进上的附加量,语义不同,\n* 这里换算成绝对坐标列表;位移未覆盖的字符交由自然排布。\n*/\nfunction codePositionAttr(name, start, charCount, deltas) {\n\tif (start === null && deltas.length === 0) return null;\n\tconst positions = [start ?? 0];\n\tconst covered = Math.min(charCount - 1, deltas.length);\n\tfor (let index = 0; index < covered; index++) positions.push(positions[index] + deltas[index]);\n\treturn positions.length === 1 ? `${name}=\"${formatNumber(positions[0])}\"` : `${name}=\"${positions.map(formatNumber).join(\" \")}\"`;\n}\nfunction resolveFontFamily(fontId, context) {\n\tif (!fontId) return null;\n\treturn context.doc.resources.fonts.find((font) => font.id === fontId)?.fontName ?? null;\n}\n/**\n* 图片:解析 MultiMedia 声明并读资源字节,缺资源或不可识别的媒体类型跳过(不阻断整页)。\n* Type 兼容标准单字母 'g' 与主流产出的 'Image' 拼写。\n*/\nasync function renderImage(object, boundary, ctm, context) {\n\tconst media = object.resourceId === null ? void 0 : context.doc.resources.medias.find((item) => item.id === object.resourceId);\n\tconst location = media?.location;\n\tconst type = media?.type?.toLowerCase();\n\tif (!location || type !== void 0 && type !== \"g\" && type !== \"image\") return \"\";\n\tlet bytes;\n\ttry {\n\t\tbytes = await context.zip.read(joinZipPath(context.doc.dir, location));\n\t} catch {\n\t\treturn \"\";\n\t}\n\tconst mime = sniffImageMime(bytes);\n\tif (!mime) return \"\";\n\tconst content = boundary === null ? null : imageContentSize(boundary, ctm);\n\treturn `<image${content === null ? \"\" : ` width=\"${formatNumber(content.width)}\" height=\"${formatNumber(content.height)}\"`} href=\"data:${mime};base64,${toBase64(bytes)}\"/>`;\n}\n/**\n* 图片内容盒尺寸:无缩放 CTM 时 Boundary 即内容盒;带缩放 CTM 的产出\n* (WPS / 新版数电发票实证)图片内容为 [0,1] 单位盒,尺寸与定位由 CTM 给出,\n* Boundary 只提供平移原点(WPS 写最终包围盒、数电票二维码写整页盒,均不参与定尺寸)。\n*/\nfunction imageContentSize(boundary, ctm) {\n\tif (!hasScaleComponent(ctm)) return {\n\t\twidth: boundary.width,\n\t\theight: boundary.height\n\t};\n\treturn {\n\t\twidth: 1,\n\t\theight: 1\n\t};\n}\n/** 按魔数识别可渲染的图片媒体类型;多帧格式(GIF/APNG)由展示端取首帧 */\nfunction sniffImageMime(bytes) {\n\tif (bytes.length >= 4 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return \"image/png\";\n\tif (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return \"image/jpeg\";\n\tif (bytes.length >= 3 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) return \"image/gif\";\n\tif (bytes.length >= 2 && bytes[0] === 66 && bytes[1] === 77) return \"image/bmp\";\n\tif (bytes.length >= 12 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) return \"image/webp\";\n\treturn null;\n}\nfunction toBase64(bytes) {\n\tlet binary = \"\";\n\tconst chunkSize = 32768;\n\tfor (let offset = 0; offset < bytes.length; offset += chunkSize) binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n\treturn btoa(binary);\n}\n/** 对象生效绘制参数:自身 FillColor/StrokeColor/LineWidth 声明优先于 DrawParam 继承链 */\nfunction resolveDrawAttributes(drawParamId, context) {\n\tconst chain = [];\n\tconst visited = /* @__PURE__ */ new Set();\n\tlet current = drawParamId === null ? void 0 : findDrawParam(drawParamId, context);\n\twhile (current && !visited.has(current.id)) {\n\t\tvisited.add(current.id);\n\t\tchain.unshift(current);\n\t\tcurrent = current.relative === null ? void 0 : findDrawParam(current.relative, context);\n\t}\n\tlet fillColor = null;\n\tlet strokeColor = null;\n\tlet lineWidth = null;\n\tfor (const declaration of chain) {\n\t\tfillColor ??= declaration.fillColor;\n\t\tstrokeColor ??= declaration.strokeColor;\n\t\tlineWidth ??= declaration.lineWidth;\n\t}\n\treturn {\n\t\tfillColor,\n\t\tstrokeColor,\n\t\tlineWidth\n\t};\n}\nfunction findDrawParam(id, context) {\n\treturn context.doc.resources.drawParams.find((param) => param.id === id);\n}\nfunction renderPath(object, context, scope) {\n\tconst d = pathD(object.commands);\n\tif (d === \"\") return \"\";\n\tconst draw = resolveDrawAttributes(object.drawParamId ?? scope.drawParamId, context);\n\tconst strokeColor = object.strokeColor ?? draw.strokeColor;\n\tconst fill = object.fillColor ?? draw.fillColor ?? (object.fill ? DEFAULT_FILL : \"none\");\n\treturn `<path ${[\n\t\t`d=\"${d}\"`,\n\t\t`fill=\"${fill}\"`,\n\t\tstrokeColor === null ? null : `stroke=\"${strokeColor}\"`,\n\t\tattr(\"stroke-width\", object.lineWidth ?? draw.lineWidth),\n\t\tlistAttr(\"stroke-dasharray\", object.dashPattern)\n\t].filter((value) => value !== null).join(\" \")}/>`;\n}\nfunction pathD(commands) {\n\treturn commands.map((command) => command.type === \"Z\" ? \"Z\" : `${command.type === \"B\" ? \"Q\" : command.type} ${command.points.map(formatNumber).join(\" \")}`).join(\" \");\n}\n/** 对象外壳 transform:CTM 矩阵 + 平移到 Boundary 原点,单位矩阵不输出 */\nfunction groupTransform(ctm, boundary) {\n\tconst matrix = isIdentityMatrix(ctm) ? null : `matrix(${ctm.map(formatNumber).join(\" \")})`;\n\tif (!boundary) return matrix ?? \"\";\n\tconst translate = `translate(${formatNumber(boundary.x)} ${formatNumber(boundary.y)})`;\n\tif (hasScaleComponent(ctm)) return matrix ? `${translate} ${matrix}` : translate;\n\treturn matrix ? `${matrix} ${translate}` : translate;\n}\n/** CTM 是否带缩放分量(旋转/切变的轴长为 1,缩放会偏离 1) */\nfunction hasScaleComponent(ctm) {\n\treturn Math.abs(Math.hypot(ctm[0], ctm[1]) - 1) > 1e-6 || Math.abs(Math.hypot(ctm[2], ctm[3]) - 1) > 1e-6;\n}\nfunction isIdentityMatrix(matrix) {\n\treturn matrix[0] === 1 && matrix[1] === 0 && matrix[2] === 0 && matrix[3] === 1 && matrix[4] === 0 && matrix[5] === 0;\n}\nfunction attr(name, value) {\n\tif (value === null) return null;\n\treturn `${name}=\"${typeof value === \"number\" ? formatNumber(value) : escapeXml(value)}\"`;\n}\nfunction listAttr(name, values) {\n\treturn values.length === 0 ? null : `${name}=\"${values.map(formatNumber).join(\" \")}\"`;\n}\nfunction escapeXml(text) {\n\treturn text.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\").replaceAll(\"\\\"\", \"&quot;\");\n}\n//#endregion\nexport { pageToSvg };\n\n//# sourceMappingURL=render.js.map"],"mappings":"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"}