@darialan/web-printer 1.0.0 → 1.0.1

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.
package/dist/index.cjs CHANGED
@@ -1,56 +1,2 @@
1
- "use strict";var Nt=Object.create;var at=Object.defineProperty;var Ct=Object.getOwnPropertyDescriptor;var Lt=Object.getOwnPropertyNames;var It=Object.getPrototypeOf,_t=Object.prototype.hasOwnProperty;var Bt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Lt(e))!_t.call(t,o)&&o!==n&&at(t,o,{get:()=>e[o],enumerable:!(r=Ct(e,o))||r.enumerable});return t};var Ft=(t,e,n)=>(n=t!=null?Nt(It(t)):{},Bt(e||!t||!t.__esModule?at(n,"default",{value:t,enumerable:!0}):n,t));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Ut=require("html2canvas"),st=72/25.4,v=25.4/96,S=96/25.4,A=t=>Number((t*v).toFixed(4)),U={"card-3x4":{widthPx:1242,heightPx:1656,marginPx:60},"square-1x1":{widthPx:1080,heightPx:1080,marginPx:54},"card-4x5":{widthPx:1080,heightPx:1350,marginPx:54},"story-9x16":{widthPx:1080,heightPx:1920,marginPx:54},"ecom-750x1000":{widthPx:750,heightPx:1e3,marginPx:0}},Ot=Object.keys(U);function ct(t){return t in U}function $t(t){return ct(t)?"px":"mm"}const K={a4:[210,297],a3:[297,420],a5:[148,210],letter:[215.9,279.4],...Object.fromEntries(Object.entries(U).map(([t,e])=>[t,[A(e.widthPx),A(e.heightPx)]]))},G={a4:{widthMm:210,heightMm:297,marginTopMm:10,marginRightMm:10,marginBottomMm:10,marginLeftMm:10},a3:{widthMm:297,heightMm:420,marginTopMm:10,marginRightMm:10,marginBottomMm:10,marginLeftMm:10},a5:{widthMm:148,heightMm:210,marginTopMm:10,marginRightMm:10,marginBottomMm:10,marginLeftMm:10},letter:{widthMm:215.9,heightMm:279.4,marginTopMm:10,marginRightMm:10,marginBottomMm:10,marginLeftMm:10},custom:{widthMm:210,heightMm:Number((200*v).toFixed(2)),marginTopMm:Number((2*v).toFixed(2)),marginRightMm:Number((2*v).toFixed(2)),marginBottomMm:Number((2*v).toFixed(2)),marginLeftMm:Number((2*v).toFixed(2))},...Object.fromEntries(Object.entries(U).map(([t,e])=>[t,{widthMm:A(e.widthPx),heightMm:A(e.heightPx),marginTopMm:A(e.marginPx),marginRightMm:A(e.marginPx),marginBottomMm:A(e.marginPx),marginLeftMm:A(e.marginPx)}]))},lt={unit:"mm",paper:"a4",widthMm:210,heightMm:297,orientation:"portrait",marginTopMm:10,marginRightMm:10,marginBottomMm:10,marginLeftMm:10,pageNumber:{enabled:!0,position:"bottom-right",format:"slash"}};function Dt(t,e="portrait",n="mm"){const r=G[t]||G.a4;let o,i;if(t==="custom")o=r.widthMm,i=r.heightMm;else{const[u,l]=K[t];o=e==="landscape"?l:u,i=e==="landscape"?u:l}const{marginTopMm:a,marginRightMm:s,marginBottomMm:d,marginLeftMm:c}=r;return n==="px"?t==="custom"?{width:Number((o*S).toFixed(1)),height:200,marginTop:2,marginRight:2,marginBottom:2,marginLeft:2}:{width:Number((o*S).toFixed(1)),height:Number((i*S).toFixed(1)),marginTop:Number((a*S).toFixed(1)),marginRight:Number((s*S).toFixed(1)),marginBottom:Number((d*S).toFixed(1)),marginLeft:Number((c*S).toFixed(1))}:{width:o,height:i,marginTop:a,marginRight:s,marginBottom:d,marginLeft:c}}function T(t){return t*st}function dt(t){const e=t.paper==="custom"?[t.widthMm,t.heightMm]:K[t.paper];if(!e||e.some(s=>!Number.isFinite(s)||s<=0))throw new Error("页面宽高必须是大于零的数值");if(!["portrait","landscape"].includes(t.orientation))throw new Error("纸张方向无效");const n=[t.marginTopMm,t.marginRightMm,t.marginBottomMm,t.marginLeftMm];if(n.some(s=>!Number.isFinite(s)||s<0))throw new Error("页边距必须为非负数");const[r,o]=[...e].sort((s,d)=>s-d),[i,a]=t.paper==="custom"?e:t.orientation==="portrait"?[r,o]:[o,r];if(i-n[1]-n[3]<=0||a-n[0]-n[2]<=0)throw new Error("页边距占满了页面,请减小边距");return{pageWidth:T(i),pageHeight:T(a),left:T(n[3]),right:T(n[1]),top:T(n[0]),bottom:T(n[2]),widthMm:i,heightMm:a}}const ut=["widthMm","heightMm","marginTopMm","marginRightMm","marginBottomMm","marginLeftMm"];function Ht(t,e){const n={...t};return ut.forEach(r=>{typeof t[r]=="number"&&(n[r]=t[r]*e)}),n}function pt(t,e,n,r,o=!0){var y;const{pageWidth:i,pageHeight:a}=t;if(!Number.isFinite(e)||e<=0||[n,r].some(E=>E!==void 0&&(!Number.isFinite(E)||E<0)))throw new Error("打印区域或页眉页脚尺寸无效");const s=typeof o=="boolean"?o:o.enabled,d=typeof o=="object"&&((y=o.position)==null?void 0:y.startsWith("top")),c=s&&d?14:0,u=s&&!d?14:0,l=i-t.left-t.right,p=l/e,m=(n||0)*p,h=(r||0)*p,g=t.top+m+(n!==void 0?6:0)+c,f=a-t.bottom-u-h,b=(f-(r!==void 0?6:0)-g)/p;if(b<=0)throw new Error("页眉页脚过高,没有剩余正文空间");return{pageWidth:i,pageHeight:a,contentWidth:l,ratio:p,headerHeight:m,footerHeight:h,bodyTop:g,left:t.left,headerY:t.top,footerY:f,pageNumberY:d?g-5:a-Math.max(6,t.bottom/2),capacity:b}}function mt(t,e,n,r=100){if(![t,e].every(Number.isFinite)||t<=0||e<=0||!Number.isSafeInteger(r)||r<1)throw new Error("打印区域或纸张尺寸无效");const o=[],i=n.map(c=>{if(!Number.isFinite(c.top)||!Number.isFinite(c.bottom)||c.bottom<c.top)throw new Error("分页测量结果无效");return{top:Math.max(0,c.top),bottom:Math.min(t,c.bottom)}}).filter(c=>c.bottom>c.top).sort((c,u)=>c.top-u.top);for(const c of i){if(c.bottom-c.top>e)throw new Error("存在超过单页高度且不可拆分的内容,请缩小图片或调整布局");const u=o[o.length-1];u&&c.top<u.bottom?u.bottom=Math.max(u.bottom,c.bottom):o.push({...c})}if(o.some(c=>c.bottom-c.top>e))throw new Error("重叠的不可拆分内容超过单页高度,无法安全分页");const a=[];let s=0,d=0;for(;s<t;){if(a.length>=r)throw new Error(`文档超过 ${r} 页限制,请拆分导出或增大页面高度`);let c=Math.min(s+e,t);if(c<t){for(;d<o.length&&o[d].bottom<=c;)d++;d<o.length&&o[d].top<c&&(c=o[d].top)}if(c<=s)throw new Error("页面高度不足,无法安全分页,请增大页面高度");a.push({start:s,end:c}),s=c}return a}function ht(t,e,n=.25){const r=t.slice(1).filter(o=>e.some(i=>i.top+n<o.start&&i.bottom-n>o.start));if(r.length)throw new Error(`分页预览与原页面布局不一致:${r.length} 个断点穿过受保护内容,首个位置 ${r[0].start.toFixed(1)}px`)}const Wt=3,zt=1,Gt={ATOMIC:'data-print-atomic="true"',SPLITTABLE:'data-print-splittable="true"',IGNORE:'data-print-ignore="true"',KEEP_TOGETHER:'data-print-keep-together="true"',KEEP_OR_SPLIT:'data-print-keep-together="split"',FORCE_SPLIT:'data-print-break="split"'},jt={ATOMIC:"print-atomic",SPLITTABLE:"print-splittable",IGNORE:"print-ignore",KEEP_TOGETHER:"print-keep-together",KEEP_OR_SPLIT:"print-keep-or-split",FORCE_SPLIT:"print-force-split"},Vt={ATOMIC:'data-pdf-atomic="true"',SPLITTABLE:'data-pdf-splittable="true"',IGNORE:'data-pdf-ignore="true"',KEEP_TOGETHER:'data-pdf-keep-together="true"',KEEP_OR_SPLIT:'data-pdf-keep-together="split"',FORCE_SPLIT:'data-pdf-break="split"'},Yt={ATOMIC:"pdf-atomic",SPLITTABLE:"pdf-splittable",IGNORE:"pdf-ignore",KEEP_TOGETHER:"pdf-keep-together",KEEP_OR_SPLIT:"pdf-keep-or-split",FORCE_SPLIT:"pdf-force-split"},D=[{selector:'script, style, template, [hidden], [data-print-debug], [data-print-ignore="true"], .print-ignore, [data-pdf-debug], [data-pdf-ignore="true"], .pdf-ignore',result:{kind:"ignore"}},{selector:'[data-print-splittable="true"], .print-splittable, [data-print-break="split"], .print-force-split, [data-pdf-splittable="true"], .pdf-splittable, [data-pdf-break="split"], .pdf-force-split',result:{kind:"container"}},{selector:'[data-print-atomic="true"], .print-atomic, [data-print-keep-together="true"], .print-keep-together, [data-pdf-atomic="true"], .pdf-atomic, [data-pdf-keep-together="true"], .pdf-keep-together',result:{kind:"atomic",label:"不可分割区域",overflow:"error"}},{selector:'[data-print-keep-together="split"], .print-keep-or-split, [data-pdf-keep-together="split"], .pdf-keep-or-split, tr',result:{kind:"atomic",label:"表格行与复合块",overflow:"split"}},{selector:"img, canvas, svg",result:{kind:"atomic",label:"图片媒体",overflow:"error"}},{selector:"h1, h2, h3, h4, h5, h6",result:{kind:"atomic",label:"标题",overflow:"error"}}],ft=D;function C(t){var o,i,a;if(!t)return[...D];const e=[];(o=t.customRules)!=null&&o.length&&e.push(...t.customRules),(i=t.ignore)!=null&&i.length&&e.push({selector:t.ignore.join(", "),result:{kind:"ignore"}});const n=[...t.splittable||[],...t.forceSplit||[]];n.length&&e.push({selector:n.join(", "),result:{kind:"container"}});const r=[...t.atomic||[],...t.keepTogether||[]];return r.length&&e.push({selector:r.join(", "),result:{kind:"atomic",label:"自定义原子项",overflow:"error"}}),(a=t.keepOrSplit)!=null&&a.length&&e.push({selector:t.keepOrSplit.join(", "),result:{kind:"atomic",label:"可降级拆分区域",overflow:"split"}}),[...e,...D]}let X=C();function qt(t){X=C(t)}function M(){return X}function Kt(){X=C()}function N(t,e=M()){var n,r;return t.nodeType===Wt?(n=t.textContent)!=null&&n.trim()?{kind:"text"}:{kind:"ignore"}:t.nodeType!==zt||typeof t.matches!="function"?{kind:"ignore"}:((r=e.find(o=>t.matches(o.selector)))==null?void 0:r.result)||{kind:"container"}}function j(t,e,n,r){if(e<=n)return"protect";if(t.overflow==="split")return"descend";const o=r||t.label;throw new Error(`不可拆分区域「${o}」高 ${Math.ceil(e)}px,超过正文可用高度 ${Math.floor(n)}px,请缩小该区域或增大页面高度`)}function H(t,e){const n=[],r=o=>{for(let i=o.childNodes.length-1;i>=0;i--)n.push(o.childNodes[i])};for(r(t);n.length;){const o=n.pop();e(o)==="descend"&&r(o)}}function Z(t,e=n=>n){const n=new WeakMap,r=document.createRange();let o=0;return i=>{var c,u;if(o+=((c=i.textContent)==null?void 0:c.length)||0,o>2e5)throw new Error("文本超过 200,000 字符限制,请拆分导出");const a=i.parentElement;if(a&&!n.has(a)){const l=((u=a.ownerDocument)==null?void 0:u.defaultView)||window,p=l.getComputedStyle?l.getComputedStyle(a).lineHeight:window.getComputedStyle(a).lineHeight;n.set(a,parseFloat(p))}const s=a?n.get(a):NaN;return r.selectNodeContents(i),(r.getClientRects?Array.from(r.getClientRects()):[]).filter(l=>l.width>0&&l.height>0).map(l=>{const p=Number.isFinite(s)?Math.max(0,s-l.height)/2:0;return{top:e(l.top-t-p),bottom:e(l.bottom-t+p)}})}}function Xt(t){const e=Z(t.getBoundingClientRect().top),n=[];return H(t,r=>{const o=N(r);return o.kind==="ignore"?"skip":o.kind==="text"?(n.push(...e(r)),"skip"):"descend"}),n}function gt(t){const e=Math.max(t.getBoundingClientRect().height,t.scrollHeight);if(e<=0||e>2e5)throw new Error("打印区域为空或超过 200,000px 高度限制");return e}function Q(t,e,n=ft){const r=t.getBoundingClientRect(),o=gt(t),i=[],a=Z(r.top),s={visitedNodes:0,atomicElements:0,textNodes:0,textFragments:0},d=N(t,n);if(d.kind==="ignore")throw new Error("打印区域已被 ignore 规则排除,请选择其他区域");if(d.kind==="atomic"&&j(d,o,e,t.getAttribute("data-print-label")||t.getAttribute("data-pdf-label")||t.getAttribute("alt"))==="protect")return{height:o,ranges:[{top:0,bottom:o}],stats:{...s,visitedNodes:1,atomicElements:1}};const c=u=>{const l=Math.max(0,u.top),p=Math.min(o,u.bottom);p>l&&i.push({top:l,bottom:p})};return H(t,u=>{s.visitedNodes++;const l=N(u,n);if(l.kind==="ignore")return"skip";if(l.kind==="container")return"descend";if(l.kind==="text"){const g=a(u);return s.textNodes++,s.textFragments+=g.length,g.forEach(c),"skip"}const p=u,m=p.getBoundingClientRect();if(m.width<=0||m.height<=0)return"skip";const h=p.getAttribute("data-print-label")||p.getAttribute("data-pdf-label")||p.getAttribute("alt");return j(l,m.height,e,h)==="descend"?"descend":(s.atomicElements++,c({top:m.top-r.top,bottom:m.bottom-r.top}),"skip")}),{height:o,ranges:i,stats:s}}function x(t){if(t!=null&&t.aborted)throw new Error("导出已取消")}async function Zt(t){for(let e=0;e<2;e++)x(t),await new Promise(n=>setTimeout(n,16));x(t)}async function J(t,e,n=M()){x(e);let r,o=()=>{};const i=new Promise((a,s)=>{r=setTimeout(()=>s(new Error("字体或图片加载超时,请稍后重试")),15e3),o=()=>s(new Error("导出已取消")),e==null||e.addEventListener("abort",o,{once:!0})});try{await Promise.race([i,(async()=>{var a;await Promise.all([(a=t.ownerDocument.fonts)==null?void 0:a.ready,...[...t.tagName==="IMG"?[t]:[],...Array.from(t.querySelectorAll("img"))].filter(s=>{for(let d=s;d;d=d.parentElement){if(N(d,n).kind==="ignore")return!1;if(d===t)break}return!0}).map(async s=>{try{await s.decode()}catch{throw new Error(`图片加载失败:${s.alt||"未命名图片"}`)}if(!s.naturalWidth)throw new Error(`图片内容为空:${s.alt||"未命名图片"}`)})]),await Zt(e)})()]),x(e)}finally{clearTimeout(r),e==null||e.removeEventListener("abort",o)}}function bt(t,e){var o;const n=((o=t.ownerDocument)==null?void 0:o.defaultView)||(typeof window<"u"?window:null),r=n!=null&&n.getComputedStyle?n.getComputedStyle(t):null;if(r){for(let i=0;i<r.length;i++){const a=r.item(i);/^(width|height|block-size|inline-size)$/.test(a)&&!/^(IMG|CANVAS|SVG|TABLE|COL|COLGROUP)$/.test(t.tagName.toUpperCase())||e.style.setProperty(a,r.getPropertyValue(a),r.getPropertyPriority(a))}e.style.animation="none",e.style.transition="none"}}function wt(t,e=M()){const n=typeof document<"u"?document:t.ownerDocument,r=n!=null&&n.importNode?n.importNode(t,!0):t.cloneNode(!0),o=[t,...Array.from(t.querySelectorAll("*"))],i=[r,...Array.from(r.querySelectorAll("*"))];o.forEach((s,d)=>{const c=i[d];if(!c||c.nodeType!==1)return;if(s!==t&&N(s,e).kind==="ignore"){c.remove();return}for(const l of Array.from(c.attributes))(/^on/i.test(l.name)||l.name==="autofocus")&&c.removeAttribute(l.name);const u=(s.tagName||"").toLowerCase();if(u==="input"){const l=s,p=c;p.value=l.value,p.checked=l.checked}else if(u==="textarea")c.value=s.value;else if(u==="select")c.selectedIndex=s.selectedIndex;else if(u==="canvas"){const l=s,p=c;p.width=l.width,p.height=l.height;try{l.toDataURL();const m=p.getContext("2d");if(!m)throw new Error("canvas context unavailable");m.drawImage(l,0,0)}catch{throw new Error("画布内容无法读取,请检查跨域图片或浏览器的画布支持")}}else if(u==="img"){const l=c;if(l.loading="eager",l.src=s.currentSrc||s.src,l.removeAttribute("srcset"),l.removeAttribute("sizes"),/^https?:/.test(l.src)&&typeof window<"u")try{new URL(l.src).origin!==window.location.origin&&(l.crossOrigin="anonymous")}catch{}}c.style&&bt(s,c)}),r.querySelectorAll('[data-print-debug], [data-print-ignore="true"], [data-pdf-debug], [data-pdf-ignore="true"]').forEach(s=>s.remove()),r.style.margin="0",r.style.setProperty("margin-inline","0"),r.style.setProperty("margin-block","0");const a=t.getBoundingClientRect().width;return a>0&&(r.style.width=`${a}px`,r.style.maxWidth="none",r.style.boxSizing="border-box"),r}function Et(t,e=M()){const n=document.createElement("div");return n.setAttribute("data-print-snapshot","true"),n.setAttribute("aria-hidden","true"),n.setAttribute("inert",""),n.style.cssText=`position:absolute;left:-100000px;top:0;width:${t}px;pointer-events:none;background:white;`,{clone:o=>{const i=wt(o,e);return i.style.width=`${t}px`,i.style.maxWidth="none",i.style.boxSizing="border-box",n.appendChild(i),i},mount:()=>document.body.appendChild(n),ready:o=>J(n,o),dispose:()=>n.remove()}}function Qt(t){const e=t.cloneNode(!0);let n=e;const r=[t,...Array.from(t.querySelectorAll("*"))],o=[e,...Array.from(e.querySelectorAll("*"))];return r.forEach((i,a)=>{const s=o[a];for(const d of Array.from(s.attributes))/^on/i.test(d.name)&&s.removeAttribute(d.name);if(i instanceof HTMLCanvasElement){const d=document.createElement("img");d.src=i.toDataURL("image/png"),d.style.cssText=s.style.cssText,d.width=i.width,d.height=i.height,s===e?n=d:s.replaceWith(d)}else i instanceof HTMLInputElement?(s.setAttribute("value",i.type==="password"?"":i.value),s.toggleAttribute("checked",i.checked)):i instanceof HTMLTextAreaElement?s.textContent=i.value:i instanceof HTMLOptionElement&&s.toggleAttribute("selected",i.selected);s.matches("a, button, input, textarea, select, [tabindex]")&&s.setAttribute("tabindex","-1")}),n.outerHTML}function Jt(t,e){const n=new Map;return t.replace(/\sid="([^"]+)"/g,(r,o)=>(n.set(o,`${e}-${o}`),r)),t.replace(/(\s(?:id|for|href|xlink:href|aria-labelledby|aria-describedby)="|url\(#)([^")]+)("|\))/g,(r,o,i,a)=>{const s=i.startsWith("#"),d=(s?i.slice(1):i).split(" ").map(c=>n.get(c)||c).join(" ");return`${o}${s?"#":""}${d}${a}`})}const te=8e6;function yt(t,e){const n=new Set,r=o=>{o.width=0,o.height=0,n.delete(o)};return{async capture(o,i,a){if(e!=null&&e.aborted)throw new Error("导出已取消");const s=Math.min(2,Math.sqrt(te/(Math.ceil(t)*Math.ceil(a))),8192/t,8192/a);if(!Number.isFinite(s)||s<.5)throw new Error("页面像素超限,请缩小打印区域宽度");const d=await Ut(o,{x:0,y:i,width:t,height:a,scale:s,useCORS:!0,allowTaint:!1,backgroundColor:"#ffffff",logging:!1,imageTimeout:15e3,ignoreElements:c=>c.hasAttribute("data-print-debug")||c.getAttribute("data-print-ignore")==="true"?!0:c.tagName==="HEAD"||c.closest("head")?!1:c!==o&&!c.contains(o)&&!o.contains(c)});if(n.add(d),e!=null&&e.aborted)throw new Error("导出已取消");if(!d.width||!d.height)throw new Error("截图为空,请检查打印区域");return d},release:r,dispose:()=>n.forEach(r)}}function tt(t,e,n){const r=t+1;switch(n){case"chinese":return`第 ${r} 页 / 共 ${e} 页`;case"hyphen":return`- ${r} -`;case"slash":default:return`${r} / ${e}`}}async function xt({geometry:t,settings:e,headerCanvas:n,footerCanvas:r,totalPages:o}){const{jsPDF:i}=await import("jspdf"),{pageWidth:a,pageHeight:s,contentWidth:d,headerHeight:c,footerHeight:u,left:l,bodyTop:p,headerY:m,footerY:h,pageNumberY:g}=t,f=a>s?"landscape":"portrait",b=new i({unit:"pt",format:[a,s],orientation:f}),y=(e==null?void 0:e.marginRightMm)!==void 0?T(e.marginRightMm):T(10);return{addPageSlice(E,R,P){E>0&&b.addPage(),b.addImage(R,"PNG",l,p,d,P,void 0,"FAST"),n&&b.addImage(n,"PNG",l,m,d,c,"print-header","FAST"),r&&b.addImage(r,"PNG",l,h,d,u,"print-footer","FAST");const w=e==null?void 0:e.pageNumber;if(w?w.enabled:!0){b.setFontSize(9),b.setTextColor(120,120,120);const L=(w==null?void 0:w.position)||"bottom-right",k=tt(E,o,w==null?void 0:w.format);let O,$;L==="bottom-center"||L==="top-center"?(O=a/2,$="center"):(O=a-y,$="right");const ot=g;if((w==null?void 0:w.format)==="chinese"){const I=document.createElement("canvas");I.width=640,I.height=48;const B=I.getContext("2d");if(!B)throw new Error("浏览器无法渲染中文页码");B.font="24px sans-serif";const kt=Math.ceil(B.measureText(k).width);B.fillStyle="#787878",B.fillText(k,0,34);const it=kt*9/24,vt=$==="center"?it/2:it;b.addImage(I,"PNG",O-vt,ot-12.75,240,18),I.width=0,I.height=0}else b.text(k,O,ot,{align:$})}},async finalize(E,R=!0){const P=b.output("blob");return R&&await b.save(`${E.replace(/\.pdf$/i,"")||"document"}.pdf`,{returnPromise:!0}),P}}}function V(t,e,n){const r=document.createElement("div");return r.className=`print-declarative-${e}`,r.style.width=`${n}px`,r.style.boxSizing="border-box",r.style.padding=e==="header"?"8px 0 6px 0":"6px 0 8px 0",r.style.textAlign=t.align||"center",r.style.fontSize=e==="header"?"12px":"11px",r.style.color=e==="header"?"#334155":"#64748b",r.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',r.style.lineHeight="1.4",t.showDivider&&(e==="header"?r.style.borderBottom="1px solid #cbd5e1":r.style.borderTop="1px solid #cbd5e1"),r.textContent=t.text||"",r}const W=new WeakSet;function Pt({root:t,capacity:e,maxPages:n,rules:r,ruleConfig:o}){const i=performance.now(),a=r||(o?C(o):M()),s=Q(t,e,a),d=performance.now();return{pages:mt(s.height,e,s.ranges,n),stats:s.stats,timing:{measurementMs:d-i,paginationMs:performance.now()-d}}}function F(t){var o,i,a;if(!t||typeof t!="object")return!1;const e=t;if(e.nodeType!==1)return!1;const n=(o=e.ownerDocument)==null?void 0:o.defaultView;return n&&typeof n.HTMLElement=="function"&&e instanceof n.HTMLElement||typeof HTMLElement<"u"&&e instanceof HTMLElement||typeof e.getBoundingClientRect=="function"&&typeof e.cloneNode=="function"?!!(e.isConnected??((a=(i=e.ownerDocument)==null?void 0:i.contains)==null?void 0:a.call(i,e))):!1}function et(t){var e,n,r;if(!F(t))return null;if(((e=t.tagName)==null?void 0:e.toLowerCase())==="iframe"){const o=t;let i;try{i=o.contentDocument||((n=o.contentWindow)==null?void 0:n.document)}catch{throw new Error("无法读取跨域 iframe,请在嵌入系统内接入打印工具或使用其导出接口")}if(!(i!=null&&i.body)||i.readyState==="loading"||i.URL==="about:blank"&&o.getAttribute("src"))throw new Error("iframe 内容尚未就绪,请等待加载完成后重试");const a=i.getElementById("iframe-report-content")||i.body;if(!F(a)||!a.childElementCount&&!((r=a.textContent)!=null&&r.trim()))throw new Error("iframe 中没有可打印的业务内容");return a}return t}async function rt(t){var p,m,h,g,f;const{header:e,footer:n,signal:r,orientation:o="portrait"}=t,i=t.maxPages??100,a=et(t.element);if(!a)throw new Error("找不到有效的打印区域");if(!["portrait","landscape"].includes(o))throw new Error("纸张方向必须为 portrait 或 landscape");const s=dt({...lt,orientation:o,...t.settings||{}});if(W.has(a))throw new Error("该区域正在导出,请勿重复提交");let d=a.getBoundingClientRect().width;if(!Number.isFinite(d)||d<=0)throw new Error("打印区域宽度为零,请先显示内容");x(r),W.add(a);const c=t.rules||(t.ruleConfig?C(t.ruleConfig):M());let u;const l=()=>{u==null||u.dispose(),W.delete(a)};try{if(await J(a,r,c),d=a.getBoundingClientRect().width,!Number.isFinite(d)||d<=0)throw new Error("打印区域宽度为零,请先显示内容");u=Et(d,c);const b=u.clone(a);let y;if(e&&F(e))y=u.clone(e);else if((m=(p=t.settings)==null?void 0:p.header)!=null&&m.enabled&&t.settings.header.text){const k=V(t.settings.header,"header",d);y=u.clone(k)}let E;if(n&&F(n))E=u.clone(n);else if((g=(h=t.settings)==null?void 0:h.footer)!=null&&g.enabled&&t.settings.footer.text){const k=V(t.settings.footer,"footer",d);E=u.clone(k)}u.mount(),await u.ready(r),x(r);const R=((f=t.settings)==null?void 0:f.pageNumber)??!0,P=pt(s,d,y==null?void 0:y.getBoundingClientRect().height,E==null?void 0:E.getBoundingClientRect().height,R),{pages:w,stats:_,timing:L}=Pt({root:b,capacity:P.capacity,maxPages:i,rules:c});return{...P,root:b,header:y,footer:E,width:d,pages:w,stats:_,timing:L,cleanup:l}}catch(b){throw l(),b}}const ee=Array.from({length:256},(t,e)=>{let n=e;for(let r=0;r<8;r++)n=n>>>1^3988292384&-(n&1);return n>>>0});function re(t){if(t.length>65535)throw new Error("图片页数超出 ZIP 限制");const e=[],n=[];let r=0,o=0;for(const{name:s,data:d}of t){const c=Uint8Array.from(s,g=>g.charCodeAt(0));let u=4294967295;for(let g=0;g<d.length;g++)u=u>>>8^ee[(u^d[g])&255];if(u=(u^4294967295)>>>0,r+d.length+c.length+30>4294967295)throw new Error("图片包超过 4GB,请分批导出");const l=new Uint8Array(30+c.length),p=new DataView(l.buffer);p.setUint32(0,67324752,!0),p.setUint16(4,20,!0),p.setUint16(12,33,!0),p.setUint32(14,u,!0),p.setUint32(18,d.length,!0),p.setUint32(22,d.length,!0),p.setUint16(26,c.length,!0),l.set(c,30);const m=new Uint8Array(46+c.length),h=new DataView(m.buffer);h.setUint32(0,33639248,!0),h.setUint16(4,20,!0),h.setUint16(6,20,!0),h.setUint16(14,33,!0),h.setUint32(16,u,!0),h.setUint32(20,d.length,!0),h.setUint32(24,d.length,!0),h.setUint16(28,c.length,!0),h.setUint32(42,r,!0),m.set(c,46),e.push(l,d),n.push(m),r+=l.length+d.length,o+=m.length}if(r+o+22>4294967295)throw new Error("图片包超过 4GB,请分批导出");const i=new Uint8Array(22),a=new DataView(i.buffer);return a.setUint32(0,101010256,!0),a.setUint16(8,t.length,!0),a.setUint16(10,t.length,!0),a.setUint32(12,o,!0),a.setUint32(16,r,!0),new Blob([...e,...n,i],{type:"application/zip"})}function ne(t){return new Promise((e,n)=>t.toBlob(r=>r?e(r):n(new Error("图片编码失败,请重试导出")),"image/png"))}function oe(t){return new Promise((e,n)=>{const r=new FileReader;r.onload=()=>e(new Uint8Array(r.result)),r.onerror=()=>n(new Error("图片读取失败,请重试导出")),r.readAsArrayBuffer(t)})}function ie({geometry:t,settings:e,headerCanvas:n,footerCanvas:r,totalPages:o,signal:i}){const a=[];return{async addPageSlice(s,d,c){var p,m,h,g;x(i);const u=document.createElement("canvas"),l=Math.min(d.width/t.contentWidth,Math.sqrt(8e6/(t.pageWidth*t.pageHeight)),8192/t.pageWidth,8192/t.pageHeight);u.width=Math.ceil(t.pageWidth*l),u.height=Math.ceil(t.pageHeight*l);try{const f=u.getContext("2d");if(!f)throw new Error("浏览器无法生成分页图片");if(f.scale(l,l),f.fillStyle="#fff",f.fillRect(0,0,t.pageWidth,t.pageHeight),f.drawImage(d,t.left,t.bodyTop,t.contentWidth,c),n&&f.drawImage(n,t.left,t.headerY,t.contentWidth,t.headerHeight),r&&f.drawImage(r,t.left,t.footerY,t.contentWidth,t.footerHeight),((p=e==null?void 0:e.pageNumber)==null?void 0:p.enabled)!==!1){const y=(h=(m=e==null?void 0:e.pageNumber)==null?void 0:m.position)==null?void 0:h.endsWith("center");f.font="9px sans-serif",f.fillStyle="#787878",f.textAlign=y?"center":"right",f.fillText(tt(s,o,(g=e==null?void 0:e.pageNumber)==null?void 0:g.format),y?t.pageWidth/2:t.pageWidth-T((e==null?void 0:e.marginRightMm)??10),t.pageNumberY)}const b=await oe(await ne(u));x(i),a.push({name:`page-${String(s+1).padStart(Math.max(3,String(o).length),"0")}.png`,data:b})}finally{u.width=0,u.height=0}},async finalize(s,d=!0){x(i);const c=re(a);if(x(i),d){const u=URL.createObjectURL(c),l=document.createElement("a");l.href=u,l.download=`${s.replace(/\.(pdf|zip|png)$/i,"")||"document"}-pages.zip`,document.body.appendChild(l);try{l.click()}finally{l.remove(),setTimeout(()=>URL.revokeObjectURL(u),6e4)}}return c},dispose(){a.length=0}}}const Tt={pdf:xt,png:ie};function nt(t){if(!Object.prototype.hasOwnProperty.call(Tt,t))throw new Error(`不支持的输出格式:${t}`)}function Mt(t,e){return nt(t),Tt[t](e)}async function Rt({format:t="pdf",filename:e,download:n=!0,onProgress:r,...o}){var g;nt(t);const i=performance.now(),a=await rt(o),{root:s,headerHeight:d,footerHeight:c,ratio:u,pages:l}=a,p=performance.now()-i;let m,h;try{m=yt(a.width,o.signal);const{capture:f,release:b}=m,y=a.header?await f(a.header,0,d/u):void 0,E=a.footer?await f(a.footer,0,c/u):void 0;h=await Mt(t,{signal:o.signal,geometry:a,settings:o.settings,headerCanvas:y,footerCanvas:E,totalPages:l.length}),r==null||r(0,l.length);for(let P=0;P<l.length;P++){x(o.signal);const w=l[P],_=await f(s,w.start,w.end-w.start);try{await h.addPageSlice(P,_,(w.end-w.start)*u)}finally{b(_)}r==null||r(P+1,l.length),await new Promise(L=>setTimeout(L,0))}x(o.signal);const R=await h.finalize(e,n);return{blob:R,pages:l.length,layoutMs:p,totalMs:performance.now()-i,bytes:R.size}}finally{(g=h==null?void 0:h.dispose)==null||g.call(h),m==null||m.dispose(),a.cleanup()}}function ae(t){return Rt({...t,format:"pdf"})}async function St({contentElement:t,...e}){var i,a;const n=performance.now(),r=et(t),o=await rt({element:r,...e});try{const s=o.pages.map(l=>l.start),d=e.rules||(e.ruleConfig?C(e.ruleConfig):M()),c=Q(o.root,o.capacity,d);ht(o.pages,c.ranges);const u={pageBreaks:s,pages:o.pages,totalHeight:c.height,capacity:o.capacity,protectedRanges:c.ranges,stats:o.stats,timing:{measurementMs:((i=o.timing)==null?void 0:i.measurementMs)??0,paginationMs:((a=o.timing)==null?void 0:a.paginationMs)??0,totalMs:performance.now()-n}};return window.dispatchEvent(new CustomEvent("print-inspection",{detail:u})),window.dispatchEvent(new CustomEvent("pdf-print-inspection",{detail:u})),u}finally{o.cleanup()}}async function se(t){return(await St(t)).pageBreaks}const Y=new Map;function At(t){(t||document).querySelectorAll("[data-print-debug]").forEach(n=>n.remove());for(const[n,r]of Array.from(Y))(!t||t===n||t.nodeType===9&&n.ownerDocument===t)&&(r(),Y.delete(n))}function ce(t,e,n=M()){var c;At(e);const r={atomic:0,splittable:0,ignore:0},o=((c=e.ownerDocument)==null?void 0:c.defaultView)||(typeof window<"u"?window:null),i=o!=null&&o.getComputedStyle?o.getComputedStyle(e):null;if(i&&i.position==="static"){const u=e.style.getPropertyValue("position"),l=e.style.getPropertyPriority("position");e.style.position="relative",Y.set(e,()=>{u?e.style.setProperty("position",u,l):e.style.removeProperty("position")})}const a=e.getBoundingClientRect(),s=i&&parseFloat(i.borderTopWidth)||0,d=i&&parseFloat(i.borderLeftWidth)||0;return H(e,u=>{if(u.nodeType!==1)return"skip";const l=u;if(l.hasAttribute("data-print-debug"))return"skip";const p=N(l,n);if(p.kind==="ignore"){r.ignore++;const f=l.getBoundingClientRect();return f.width>0&&f.height>0&&e.appendChild(z({left:f.left-a.left-d,top:f.top-a.top-s,width:f.width,height:f.height,borderColor:"#94a3b8",borderStyle:"dashed",backgroundColor:"rgba(148, 163, 184, 0.08)",badgeText:"ignore",badgeBg:"#64748b",badgePosition:"left"})),"skip"}const m=l.getBoundingClientRect();if(m.width<=0||m.height<=0)return"skip";if(p.kind==="atomic")return r.atomic++,e.appendChild(z({left:m.left-a.left-d,top:m.top-a.top-s,width:m.width,height:m.height,borderColor:"#ef4444",borderStyle:"solid",backgroundColor:"rgba(239, 68, 68, 0.05)",badgeText:"atomic",badgeBg:"#ef4444",badgePosition:"right"})),"skip";if(pe(l,o))return"skip";const h=l.matches(le),g=ue(l);return h||g?(r.splittable++,e.appendChild(z({left:m.left-a.left-d,top:m.top-a.top-s,width:m.width,height:m.height,borderColor:"#3b82f6",borderStyle:"dashed",backgroundColor:"rgba(59, 130, 246, 0.04)",badgeText:"splittable",badgeBg:"#3b82f6",badgePosition:"right"})),h?"descend":"skip"):"descend"}),t.slice(1).forEach((u,l)=>{const p=u-s,m=e.ownerDocument.createElement("div");m.setAttribute("data-print-debug","true"),m.style.cssText=`
2
- position: absolute;
3
- left: 0;
4
- top: ${p}px;
5
- width: 100%;
6
- height: 0;
7
- border-top: 2px dashed #7c3aed;
8
- z-index: ${q.line};
9
- pointer-events: none;
10
- box-sizing: border-box;
11
- `;const h=e.ownerDocument.createElement("span");h.textContent=`✂️ page-break: ${Math.round(u)}px (p.${l+1} ➔ p.${l+2})`,h.style.cssText=`
12
- position: absolute;
13
- right: 16px;
14
- top: -11px;
15
- background: #7c3aed;
16
- color: #fff;
17
- font-size: 11px;
18
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
19
- line-height: 1;
20
- padding: 3px 8px;
21
- border-radius: 10px;
22
- font-weight: 600;
23
- letter-spacing: 0.2px;
24
- box-shadow: 0 1px 4px rgba(124, 58, 237, 0.35);
25
- white-space: nowrap;
26
- `,m.appendChild(h),e.appendChild(m)}),r}const le='[data-print-splittable="true"], .print-splittable, [data-print-break="split"], .print-force-split, [data-pdf-splittable="true"], .pdf-splittable, [data-pdf-break="split"], .pdf-force-split',q={box:2,badge:3,line:4},de=new Set(["SPAN","B","STRONG","EM","I","CODE","A","SMALL","SUP","SUB","MARK","ABBR","CITE","Q","TIME","U","S","KBD","SAMP","VAR","BR"]);function ue(t){var e;for(let n=0;n<t.childNodes.length;n++){const r=t.childNodes[n];if(r.nodeType===3&&((e=r.textContent)!=null&&e.trim()))return!0}return!1}function pe(t,e){return de.has(t.tagName)?!0:e!=null&&e.getComputedStyle?e.getComputedStyle(t).display.startsWith("inline"):!1}function z(t){const e=document.createElement("div");e.setAttribute("data-print-debug","true"),e.style.cssText=`
27
- position: absolute;
28
- left: ${t.left}px;
29
- top: ${t.top}px;
30
- width: ${t.width}px;
31
- height: ${t.height}px;
32
- border: 1.5px ${t.borderStyle} ${t.borderColor};
33
- background: ${t.backgroundColor};
34
- box-sizing: border-box;
35
- z-index: ${q.box};
36
- pointer-events: none;
37
- border-radius: 2px;
38
- `;const n=document.createElement("span");n.textContent=t.badgeText;const r=t.badgePosition==="right",o="2px",i=r?"right: 4px;":"left: 4px;";return n.style.cssText=`
39
- position: absolute;
40
- ${i}
41
- top: ${o};
42
- background: ${t.badgeBg};
43
- color: #ffffff;
44
- font-size: 9px;
45
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
46
- font-weight: 600;
47
- line-height: 1;
48
- padding: 1.5px 5px;
49
- border-radius: 3px;
50
- white-space: nowrap;
51
- box-shadow: 0 1px 2px rgba(0,0,0,0.18);
52
- z-index: ${q.badge};
53
- opacity: 0.95;
54
- letter-spacing: 0.2px;
55
- `,e.appendChild(n),e}exports.BASE_PRINT_RULES=D;exports.DEFAULT_PRINT_RULES=ft;exports.DEFAULT_SETTINGS=lt;exports.IMAGE_PAPERS=Ot;exports.IMAGE_PAPER_SIZES=U;exports.MM_PER_PX=v;exports.PAPER_PRESETS=G;exports.PAPER_SIZES=K;exports.PDF_PRINT_ATTRIBUTES=Vt;exports.PDF_PRINT_CLASSES=Yt;exports.PRINT_ATTRIBUTES=Gt;exports.PRINT_CLASSES=jt;exports.PT_PER_MM=st;exports.PX_PER_MM=S;exports.UNIT_FIELDS=ut;exports.buildPrintRules=C;exports.calculateGeometry=pt;exports.calculatePagesArray=se;exports.checkCancelled=x;exports.classifyPrintNode=N;exports.clearPageBreaks=At;exports.cloneWithResolvedStyles=wt;exports.configurePrint=qt;exports.convertFields=Ht;exports.copyResolvedStyle=bt;exports.createDeclarativeElement=V;exports.createOutputWriter=Mt;exports.createPageCapture=yt;exports.createPdfWriter=xt;exports.createPrintSnapshot=Et;exports.createTextMeasurer=Z;exports.formatPageNumber=tt;exports.getPresetDimensions=Dt;exports.getPresetUnit=$t;exports.getPrintRules=M;exports.inspectPrintLayout=St;exports.isImagePaper=ct;exports.isPrintableElement=F;exports.measureDocument=Q;exports.measureTextLines=Xt;exports.mmToPt=T;exports.namespacePreviewHtml=Jt;exports.outputDocument=Rt;exports.outputPDF=ae;exports.paginate=mt;exports.planDocument=Pt;exports.prepareLayout=rt;exports.readRootHeight=gt;exports.resetPrintRules=Kt;exports.resolveAtomicOverflow=j;exports.resolvePaper=dt;exports.resolvePrintElement=et;exports.serializePrintSnapshot=Qt;exports.validateOutputFormat=nt;exports.validatePageBreaks=ht;exports.visualizePageBreaks=ce;exports.waitForResources=J;exports.walkPrintTree=H;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./page-break-overlay-50796a2a.js");require("html2canvas");async function y(s){var h,T,_;const i=new AbortController,g=()=>i.abort();(h=s.signal)==null||h.addEventListener("abort",g,{once:!0}),(T=s.signal)!=null&&T.aborted&&i.abort();const f=performance.now();let t;try{t=await e.prepareLayout({...s,signal:i.signal})}catch(r){throw(_=s.signal)==null||_.removeEventListener("abort",g),r}const l=e.createPageCapture(t.width,i.signal),m=s.settings?JSON.parse(JSON.stringify(s.settings)):void 0;let E=!1,c=!1;const p=()=>{if(E)throw new Error("打印会话已关闭,请重新生成预览");if(e.checkCancelled(i.signal),c)throw new Error("正在处理上一项任务,请稍候")},R=performance.now()-f;return{layout:t,preparedMs:R,async thumbnail(r,P=480){if(p(),!Number.isInteger(r)||r<0||r>=t.pages.length)throw new Error("预览页码无效");c=!0;let n,a;try{const o=t.pages[r],u=await l.capture(t.root,o.start,o.end-o.start);try{const d=t.header?await l.capture(t.header,0,t.headerHeight/t.ratio):void 0,S=t.footer?await l.capture(t.footer,0,t.footerHeight/t.ratio):void 0;try{n=e.composePageCanvas(u,(o.end-o.start)*t.ratio,r,{geometry:t,settings:m,headerCanvas:d,footerCanvas:S,totalPages:t.pages.length})}finally{d&&l.release(d),S&&l.release(S)}}finally{l.release(u)}a=document.createElement("canvas"),a.width=Math.max(1,Math.min(640,P,n.width)),a.height=Math.ceil(n.height*a.width/n.width);const v=a.getContext("2d");if(!v)throw new Error("浏览器无法生成预览");return v.drawImage(n,0,0,a.width,a.height),e.checkCancelled(i.signal),a.toDataURL("image/jpeg",.85)}finally{n&&(n.width=0,n.height=0),a&&(a.width=0,a.height=0),c=!1}},async exportDocument(r){var a,o,u;p(),c=!0;const P=new AbortController,n=()=>P.abort();i.signal.addEventListener("abort",n,{once:!0}),(a=r.signal)==null||a.addEventListener("abort",n,{once:!0}),((o=r.signal)!=null&&o.aborted||i.signal.aborted)&&P.abort();try{return await e.exportPreparedLayout(t,{...r,settings:m,signal:P.signal},R)}finally{i.signal.removeEventListener("abort",n),(u=r.signal)==null||u.removeEventListener("abort",n),c=!1}},dispose(){var r;E||(E=!0,i.abort(),l.dispose(),t.cleanup(),(r=s.signal)==null||r.removeEventListener("abort",g))}}}exports.BASE_PRINT_RULES=e.BASE_PRINT_RULES;exports.DEFAULT_PRINT_RULES=e.DEFAULT_PRINT_RULES;exports.DEFAULT_SETTINGS=e.DEFAULT_SETTINGS;exports.IMAGE_PAPERS=e.IMAGE_PAPERS;exports.IMAGE_PAPER_SIZES=e.IMAGE_PAPER_SIZES;exports.MM_PER_PX=e.MM_PER_PX;exports.PAPER_PRESETS=e.PAPER_PRESETS;exports.PAPER_SIZES=e.PAPER_SIZES;exports.PDF_PRINT_ATTRIBUTES=e.PDF_PRINT_ATTRIBUTES;exports.PDF_PRINT_CLASSES=e.PDF_PRINT_CLASSES;exports.PRINT_ATTRIBUTES=e.PRINT_ATTRIBUTES;exports.PRINT_CLASSES=e.PRINT_CLASSES;exports.PT_PER_MM=e.PT_PER_MM;exports.PX_PER_MM=e.PX_PER_MM;exports.UNIT_FIELDS=e.UNIT_FIELDS;exports.buildPrintRules=e.buildPrintRules;exports.calculateGeometry=e.calculateGeometry;exports.calculatePagesArray=e.calculatePagesArray;exports.checkCancelled=e.checkCancelled;exports.classifyPrintNode=e.classifyPrintNode;exports.clearPageBreaks=e.clearPageBreaks;exports.cloneWithResolvedStyles=e.cloneWithResolvedStyles;exports.configurePrint=e.configurePrint;exports.convertFields=e.convertFields;exports.copyResolvedStyle=e.copyResolvedStyle;exports.createDeclarativeElement=e.createDeclarativeElement;exports.createOutputWriter=e.createOutputWriter;exports.createPageCapture=e.createPageCapture;exports.createPdfWriter=e.createPdfWriter;exports.createPrintSnapshot=e.createPrintSnapshot;exports.createTextMeasurer=e.createTextMeasurer;exports.exportPreparedLayout=e.exportPreparedLayout;exports.formatPageNumber=e.formatPageNumber;exports.getPresetDimensions=e.getPresetDimensions;exports.getPresetUnit=e.getPresetUnit;exports.getPrintRules=e.getPrintRules;exports.inspectPrintLayout=e.inspectPrintLayout;exports.isImagePaper=e.isImagePaper;exports.isPrintableElement=e.isPrintableElement;exports.measureDocument=e.measureDocument;exports.measureTextLines=e.measureTextLines;exports.mmToPt=e.mmToPt;exports.namespacePreviewHtml=e.namespacePreviewHtml;exports.outputDocument=e.outputDocument;exports.outputPDF=e.outputPDF;exports.paginate=e.paginate;exports.planDocument=e.planDocument;exports.prepareLayout=e.prepareLayout;exports.readRootHeight=e.readRootHeight;exports.resetPrintRules=e.resetPrintRules;exports.resolveAtomicOverflow=e.resolveAtomicOverflow;exports.resolvePaper=e.resolvePaper;exports.resolvePrintElement=e.resolvePrintElement;exports.serializePrintSnapshot=e.serializePrintSnapshot;exports.validateOutputFormat=e.validateOutputFormat;exports.validatePageBreaks=e.validatePageBreaks;exports.visualizePageBreaks=e.visualizePageBreaks;exports.waitForResources=e.waitForResources;exports.walkPrintTree=e.walkPrintTree;exports.createPrintSession=y;
56
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/core/geometry/paper.ts","../src/lib/core/geometry/page-geometry.ts","../src/lib/core/pagination/paginator.ts","../src/lib/core/rules/print-rules.ts","../src/lib/adapters/dom/traversal.ts","../src/lib/adapters/dom/text-range.ts","../src/lib/adapters/dom/measurement.ts","../src/lib/application/cancellation.ts","../src/lib/adapters/resources/resource-loader.ts","../src/lib/adapters/dom/snapshot.ts","../src/lib/adapters/canvas/page-capture.ts","../src/lib/output/page-number.ts","../src/lib/adapters/pdf/jspdf-writer.ts","../src/lib/application/print-pipeline.ts","../src/lib/output/zip.ts","../src/lib/output/image-writer.ts","../src/lib/output/index.ts","../src/lib/application/print-service.ts","../src/lib/overlay/page-break-overlay.ts"],"sourcesContent":["import { Orientation, Paper, PrintSettings } from '../types';\nexport type { Orientation, Paper, PrintSettings } from '../types';\n\nexport const PT_PER_MM = 72 / 25.4;\nexport const MM_PER_PX = 25.4 / 96;\nexport const PX_PER_MM = 96 / 25.4;\n\nconst pxToMm = (px: number) => Number((px * MM_PER_PX).toFixed(4));\n\n/** 社媒 / 图片画框:以像素定义,边距按画框宽度的内边距给默认值 */\nexport const IMAGE_PAPER_SIZES = {\n 'card-3x4': { widthPx: 1242, heightPx: 1656, marginPx: 60 },\n 'square-1x1': { widthPx: 1080, heightPx: 1080, marginPx: 54 },\n 'card-4x5': { widthPx: 1080, heightPx: 1350, marginPx: 54 },\n 'story-9x16': { widthPx: 1080, heightPx: 1920, marginPx: 54 },\n 'ecom-750x1000': { widthPx: 750, heightPx: 1000, marginPx: 0 },\n} as const;\n\nexport type ImagePaper = keyof typeof IMAGE_PAPER_SIZES;\n\nexport const IMAGE_PAPERS = Object.keys(IMAGE_PAPER_SIZES) as ImagePaper[];\n\nexport function isImagePaper(paper: Paper): paper is ImagePaper {\n return paper in IMAGE_PAPER_SIZES;\n}\n\n/** 预设自带的自然单位:纸张用 mm,社媒图片用 px,选中时自动切换,避免出现 328.61 mm 这种数字 */\nexport function getPresetUnit(paper: Paper): 'mm' | 'px' {\n return isImagePaper(paper) ? 'px' : 'mm';\n}\n\nexport const PAPER_SIZES: Record<Exclude<Paper, 'custom'>, [number, number]> = {\n a4: [210, 297],\n a3: [297, 420],\n a5: [148, 210],\n letter: [215.9, 279.4],\n ...Object.fromEntries(\n Object.entries(IMAGE_PAPER_SIZES).map(([key, preset]) => [\n key,\n [pxToMm(preset.widthPx), pxToMm(preset.heightPx)],\n ])\n ) as Record<ImagePaper, [number, number]>,\n};\n\n\nexport interface PaperPreset {\n widthMm: number;\n heightMm: number;\n marginTopMm: number;\n marginRightMm: number;\n marginBottomMm: number;\n marginLeftMm: number;\n}\n\n/**\n * 各纸张预设标准(基准存储单位:mm):\n * - A4、A3、A5、Letter 具有固定的标准物理宽高与统一默认页边距(10mm)\n * - 自定义尺寸(custom):\n * - 宽默认为 A4 纸宽度:210 mm (96 DPI 下对应 793.7 px)\n * - 高度默认为 200 px (对应 200 * 25.4 / 96 ≈ 52.92 mm)\n * - 上下左右边距默认为 2 px (对应 2 * 25.4 / 96 ≈ 0.53 mm)\n */\nexport const PAPER_PRESETS: Record<Paper, PaperPreset> = {\n a4: {\n widthMm: 210,\n heightMm: 297,\n marginTopMm: 10,\n marginRightMm: 10,\n marginBottomMm: 10,\n marginLeftMm: 10,\n },\n a3: {\n widthMm: 297,\n heightMm: 420,\n marginTopMm: 10,\n marginRightMm: 10,\n marginBottomMm: 10,\n marginLeftMm: 10,\n },\n a5: {\n widthMm: 148,\n heightMm: 210,\n marginTopMm: 10,\n marginRightMm: 10,\n marginBottomMm: 10,\n marginLeftMm: 10,\n },\n letter: {\n widthMm: 215.9,\n heightMm: 279.4,\n marginTopMm: 10,\n marginRightMm: 10,\n marginBottomMm: 10,\n marginLeftMm: 10,\n },\n custom: {\n widthMm: 210,\n heightMm: Number((200 * MM_PER_PX).toFixed(2)),\n marginTopMm: Number((2 * MM_PER_PX).toFixed(2)),\n marginRightMm: Number((2 * MM_PER_PX).toFixed(2)),\n marginBottomMm: Number((2 * MM_PER_PX).toFixed(2)),\n marginLeftMm: Number((2 * MM_PER_PX).toFixed(2)),\n },\n ...Object.fromEntries(\n Object.entries(IMAGE_PAPER_SIZES).map(([key, preset]) => [\n key,\n {\n widthMm: pxToMm(preset.widthPx),\n heightMm: pxToMm(preset.heightPx),\n marginTopMm: pxToMm(preset.marginPx),\n marginRightMm: pxToMm(preset.marginPx),\n marginBottomMm: pxToMm(preset.marginPx),\n marginLeftMm: pxToMm(preset.marginPx),\n },\n ])\n ) as Record<ImagePaper, PaperPreset>,\n};\n\nexport const DEFAULT_SETTINGS: PrintSettings = {\n unit: 'mm',\n paper: 'a4',\n widthMm: 210,\n heightMm: 297,\n orientation: 'portrait',\n marginTopMm: 10,\n marginRightMm: 10,\n marginBottomMm: 10,\n marginLeftMm: 10,\n pageNumber: {\n enabled: true,\n position: 'bottom-right',\n format: 'slash',\n },\n};\n\n/**\n * 根据纸张类型、纸张方向以及目标单位获取联动标准数值\n */\nexport function getPresetDimensions(\n paper: Paper,\n orientation: Orientation = 'portrait',\n unit: 'mm' | 'px' = 'mm'\n): {\n width: number;\n height: number;\n marginTop: number;\n marginRight: number;\n marginBottom: number;\n marginLeft: number;\n} {\n const preset = PAPER_PRESETS[paper] || PAPER_PRESETS.a4;\n let widthMm: number;\n let heightMm: number;\n\n if (paper === 'custom') {\n widthMm = preset.widthMm;\n heightMm = preset.heightMm;\n } else {\n const [short, long] = PAPER_SIZES[paper];\n widthMm = orientation === 'landscape' ? long : short;\n heightMm = orientation === 'landscape' ? short : long;\n }\n\n const { marginTopMm, marginRightMm, marginBottomMm, marginLeftMm } = preset;\n\n if (unit === 'px') {\n if (paper === 'custom') {\n return {\n width: Number((widthMm * PX_PER_MM).toFixed(1)),\n height: 200,\n marginTop: 2,\n marginRight: 2,\n marginBottom: 2,\n marginLeft: 2,\n };\n }\n return {\n width: Number((widthMm * PX_PER_MM).toFixed(1)),\n height: Number((heightMm * PX_PER_MM).toFixed(1)),\n marginTop: Number((marginTopMm * PX_PER_MM).toFixed(1)),\n marginRight: Number((marginRightMm * PX_PER_MM).toFixed(1)),\n marginBottom: Number((marginBottomMm * PX_PER_MM).toFixed(1)),\n marginLeft: Number((marginLeftMm * PX_PER_MM).toFixed(1)),\n };\n }\n\n return {\n width: widthMm,\n height: heightMm,\n marginTop: marginTopMm,\n marginRight: marginRightMm,\n marginBottom: marginBottomMm,\n marginLeft: marginLeftMm,\n };\n}\n\nexport function mmToPt(mm: number) {\n return mm * PT_PER_MM;\n}\n\nexport function resolvePaper(settings: PrintSettings) {\n const size = settings.paper === 'custom' ? [settings.widthMm, settings.heightMm] : PAPER_SIZES[settings.paper];\n if (!size || size.some(value => !Number.isFinite(value) || value <= 0)) {\n throw new Error('页面宽高必须是大于零的数值');\n }\n if (!['portrait', 'landscape'].includes(settings.orientation)) {\n throw new Error('纸张方向无效');\n }\n const margins = [settings.marginTopMm, settings.marginRightMm, settings.marginBottomMm, settings.marginLeftMm];\n if (margins.some(value => !Number.isFinite(value) || value < 0)) {\n throw new Error('页边距必须为非负数');\n }\n const [short, long] = [...size].sort((a, b) => a - b);\n const [widthMm, heightMm] =\n settings.paper === 'custom' ? size : settings.orientation === 'portrait' ? [short, long] : [long, short];\n if (widthMm - margins[1] - margins[3] <= 0 || heightMm - margins[0] - margins[2] <= 0) {\n throw new Error('页边距占满了页面,请减小边距');\n }\n return {\n pageWidth: mmToPt(widthMm),\n pageHeight: mmToPt(heightMm),\n left: mmToPt(margins[3]),\n right: mmToPt(margins[1]),\n top: mmToPt(margins[0]),\n bottom: mmToPt(margins[2]),\n widthMm,\n heightMm,\n };\n}\n\nexport type ResolvedPaper = ReturnType<typeof resolvePaper>;\n\nexport const UNIT_FIELDS = ['widthMm', 'heightMm', 'marginTopMm', 'marginRightMm', 'marginBottomMm', 'marginLeftMm'] as const;\n\n/** Storage stays in mm; px means CSS pixels at 96 DPI, independent of devicePixelRatio. */\nexport function convertFields<T extends PrintSettings>(value: T, factor: number): T {\n const next = { ...value };\n UNIT_FIELDS.forEach(field => {\n if (typeof value[field] === 'number') next[field] = value[field] * factor;\n });\n return next;\n}\n","import { ResolvedPaper } from './paper';\nimport { PageNumberConfig } from '../types';\n\nexport interface PageGeometry {\n pageWidth: number;\n pageHeight: number;\n contentWidth: number;\n ratio: number;\n headerHeight: number;\n footerHeight: number;\n bodyTop: number;\n left: number;\n headerY: number;\n footerY: number;\n pageNumberY: number;\n capacity: number;\n}\n\n/** Paper units (pt) and DOM units (CSS px) meet only at this boundary. */\nexport function calculateGeometry(\n paper: ResolvedPaper,\n width: number,\n headerPx: number | undefined,\n footerPx: number | undefined,\n pageNumber: boolean | PageNumberConfig = true\n): PageGeometry {\n const { pageWidth, pageHeight } = paper;\n if (!Number.isFinite(width) || width <= 0 || [headerPx, footerPx].some(value => value !== undefined && (!Number.isFinite(value) || value < 0))) {\n throw new Error('打印区域或页眉页脚尺寸无效');\n }\n const hasPageNumber = typeof pageNumber === 'boolean' ? pageNumber : pageNumber.enabled;\n const numberAtTop = typeof pageNumber === 'object' && pageNumber.position?.startsWith('top');\n const topReserve = hasPageNumber && numberAtTop ? 14 : 0;\n const bottomReserve = hasPageNumber && !numberAtTop ? 14 : 0;\n const contentWidth = pageWidth - paper.left - paper.right;\n const ratio = contentWidth / width;\n const headerHeight = (headerPx || 0) * ratio;\n const footerHeight = (footerPx || 0) * ratio;\n const bodyTop = paper.top + headerHeight + (headerPx !== undefined ? 6 : 0) + topReserve;\n const footerY = pageHeight - paper.bottom - bottomReserve - footerHeight;\n const capacity = (footerY - (footerPx !== undefined ? 6 : 0) - bodyTop) / ratio;\n if (capacity <= 0) throw new Error('页眉页脚过高,没有剩余正文空间');\n return {\n pageWidth,\n pageHeight,\n contentWidth,\n ratio,\n headerHeight,\n footerHeight,\n bodyTop,\n left: paper.left,\n headerY: paper.top,\n footerY,\n pageNumberY: numberAtTop ? bodyTop - 5 : pageHeight - Math.max(6, paper.bottom / 2),\n capacity,\n };\n}\n","import { Interval, PageSlice } from '../types';\nexport type { Interval, PageSlice } from '../types';\n\n/** CSS-pixel intervals relative to the print root. No DOM or UI dependencies. */\nexport function paginate(height: number, capacity: number, protectedRanges: Interval[], maxPages = 100): PageSlice[] {\n if (![height, capacity].every(Number.isFinite) || height <= 0 || capacity <= 0 || !Number.isSafeInteger(maxPages) || maxPages < 1) {\n throw new Error('打印区域或纸张尺寸无效');\n }\n // Merge overlapping protections once. Repeatedly scanning every line for every\n // page used to be quadratic for overlapping inline text fragments.\n const ranges: Interval[] = [];\n const sorted = protectedRanges.map(range => {\n if (!Number.isFinite(range.top) || !Number.isFinite(range.bottom) || range.bottom < range.top) {\n throw new Error('分页测量结果无效');\n }\n return { top: Math.max(0, range.top), bottom: Math.min(height, range.bottom) };\n }).filter(range => range.bottom > range.top).sort((a, b) => a.top - b.top);\n for (const range of sorted) {\n if (range.bottom - range.top > capacity) {\n throw new Error('存在超过单页高度且不可拆分的内容,请缩小图片或调整布局');\n }\n const previous = ranges[ranges.length - 1];\n if (previous && range.top < previous.bottom) previous.bottom = Math.max(previous.bottom, range.bottom);\n else ranges.push({ ...range });\n }\n if (ranges.some(range => range.bottom - range.top > capacity)) {\n throw new Error('重叠的不可拆分内容超过单页高度,无法安全分页');\n }\n const pages: PageSlice[] = [];\n let start = 0;\n let cursor = 0;\n while (start < height) {\n if (pages.length >= maxPages) throw new Error(`文档超过 ${maxPages} 页限制,请拆分导出或增大页面高度`);\n let end = Math.min(start + capacity, height);\n if (end < height) {\n while (cursor < ranges.length && ranges[cursor].bottom <= end) cursor++;\n if (cursor < ranges.length && ranges[cursor].top < end) end = ranges[cursor].top;\n }\n if (end <= start) throw new Error('页面高度不足,无法安全分页,请增大页面高度');\n pages.push({ start, end });\n start = end;\n }\n return pages;\n}\n\n/** Verify that planned page breaks do not cut through protected intervals. */\nexport function validatePageBreaks(pages: PageSlice[], ranges: Interval[], tolerance = 0.25) {\n const intersections = pages.slice(1).filter(page => ranges.some(range =>\n range.top + tolerance < page.start && range.bottom - tolerance > page.start));\n if (intersections.length) {\n throw new Error(`分页预览与原页面布局不一致:${intersections.length} 个断点穿过受保护内容,首个位置 ${intersections[0].start.toFixed(1)}px`);\n }\n}\n","import { ElementRule, PrintRule, PrintRuleConfig } from '../types';\nexport type { ElementRule, PrintRule, PrintRuleConfig } from '../types';\n\nexport interface ClassifiableNode {\n nodeType: number;\n textContent?: string | null;\n matches?: (selector: string) => boolean;\n}\n\nconst TEXT_NODE_TYPE = 3;\nconst ELEMENT_NODE_TYPE = 1;\n\n/**\n * 打印系统三大标准属性协议 (Data Attributes & Classes)\n * 纯原生技术无关的标准协议,业务方自写组件或页面时直接绑定:\n * 1. atomic: 最小原子单元,不可分割,跨页整块推移\n * 2. splittable: 可分割流式内容,允许分页线从中穿透\n * 3. ignore: 不打印,完全排除在打印纸张外\n */\nexport const PRINT_ATTRIBUTES = {\n /** 不可分割:最小原子化单元,严禁跨页切断,当前页放不下整块换到下一页 */\n ATOMIC: 'data-print-atomic=\"true\"',\n /** 可分割:声明为流式内容,允许分页线直接穿透内部 */\n SPLITTABLE: 'data-print-splittable=\"true\"',\n /** 打印忽略:不参与测量、快照与打印渲染 */\n IGNORE: 'data-print-ignore=\"true\"',\n\n // 兼容别名\n KEEP_TOGETHER: 'data-print-keep-together=\"true\"',\n KEEP_OR_SPLIT: 'data-print-keep-together=\"split\"',\n FORCE_SPLIT: 'data-print-break=\"split\"',\n} as const;\n\nexport const PRINT_CLASSES = {\n ATOMIC: 'print-atomic',\n SPLITTABLE: 'print-splittable',\n IGNORE: 'print-ignore',\n\n // 兼容别名\n KEEP_TOGETHER: 'print-keep-together',\n KEEP_OR_SPLIT: 'print-keep-or-split',\n FORCE_SPLIT: 'print-force-split',\n} as const;\n\n/** @deprecated Use PRINT_ATTRIBUTES. Legacy attributes remain accepted. */\nexport const PDF_PRINT_ATTRIBUTES = {\n ATOMIC: 'data-pdf-atomic=\"true\"', SPLITTABLE: 'data-pdf-splittable=\"true\"',\n IGNORE: 'data-pdf-ignore=\"true\"', KEEP_TOGETHER: 'data-pdf-keep-together=\"true\"',\n KEEP_OR_SPLIT: 'data-pdf-keep-together=\"split\"', FORCE_SPLIT: 'data-pdf-break=\"split\"',\n} as const;\n/** @deprecated Use PRINT_CLASSES. Legacy classes remain accepted. */\nexport const PDF_PRINT_CLASSES = {\n ATOMIC: 'pdf-atomic', SPLITTABLE: 'pdf-splittable', IGNORE: 'pdf-ignore',\n KEEP_TOGETHER: 'pdf-keep-together', KEEP_OR_SPLIT: 'pdf-keep-or-split', FORCE_SPLIT: 'pdf-force-split',\n} as const;\n\n/**\n * 核心基础规则(BASE_PRINT_RULES)\n * 遵循技术无关、纯原生标准原则:只包含 HTML 标准元素与通用打印协议,绝不硬编码任何具体前端组件库类名\n */\nexport const BASE_PRINT_RULES: readonly PrintRule[] = [\n // 1. 忽略规则(不打印:标准不可见标签与协议标记)\n {\n selector: 'script, style, template, [hidden], [data-print-debug], [data-print-ignore=\"true\"], .print-ignore, [data-pdf-debug], [data-pdf-ignore=\"true\"], .pdf-ignore',\n result: { kind: 'ignore' },\n },\n // 2. 自由可分割规则(流式容器与段落流,允许分页线穿透)\n {\n selector: '[data-print-splittable=\"true\"], .print-splittable, [data-print-break=\"split\"], .print-force-split, [data-pdf-splittable=\"true\"], .pdf-splittable, [data-pdf-break=\"split\"], .pdf-force-split',\n result: { kind: 'container' },\n },\n // 3. 不可分割规则(显式声明的原子保护块:严禁拆分,超高报错)\n {\n selector:\n '[data-print-atomic=\"true\"], .print-atomic, [data-print-keep-together=\"true\"], .print-keep-together, [data-pdf-atomic=\"true\"], .pdf-atomic, [data-pdf-keep-together=\"true\"], .pdf-keep-together',\n result: { kind: 'atomic', label: '不可分割区域', overflow: 'error' },\n },\n // 4. 不可分割规则(表格行与复合原子项:放不下整块换页,超高深入拆分)\n {\n selector: '[data-print-keep-together=\"split\"], .print-keep-or-split, [data-pdf-keep-together=\"split\"], .pdf-keep-or-split, tr',\n result: { kind: 'atomic', label: '表格行与复合块', overflow: 'split' },\n },\n // 5. 原生不可切图片媒体与标题\n {\n selector: 'img, canvas, svg',\n result: { kind: 'atomic', label: '图片媒体', overflow: 'error' },\n },\n {\n selector: 'h1, h2, h3, h4, h5, h6',\n result: { kind: 'atomic', label: '标题', overflow: 'error' },\n },\n];\n\nexport const DEFAULT_PRINT_RULES: readonly PrintRule[] = BASE_PRINT_RULES;\n\n/**\n * 根据基础规则与配置构造最终生效的规则列表\n */\nexport function buildPrintRules(config?: PrintRuleConfig): PrintRule[] {\n if (!config) return [...BASE_PRINT_RULES];\n\n const customList: PrintRule[] = [];\n\n // 用户完全自定义的高级规则优先\n if (config.customRules?.length) {\n customList.push(...config.customRules);\n }\n\n // 自定义忽略(不打印)\n if (config.ignore?.length) {\n customList.push({\n selector: config.ignore.join(', '),\n result: { kind: 'ignore' },\n });\n }\n\n // 自定义自由可分割内容(splittable)\n const splittableSelectors = [\n ...(config.splittable || []),\n ...(config.forceSplit || []),\n ];\n if (splittableSelectors.length) {\n customList.push({\n selector: splittableSelectors.join(', '),\n result: { kind: 'container' },\n });\n }\n\n // 自定义不可分割原子项(atomic)\n const atomicSelectors = [\n ...(config.atomic || []),\n ...(config.keepTogether || []),\n ];\n if (atomicSelectors.length) {\n customList.push({\n selector: atomicSelectors.join(', '),\n result: { kind: 'atomic', label: '自定义原子项', overflow: 'error' },\n });\n }\n\n if (config.keepOrSplit?.length) customList.push({\n selector: config.keepOrSplit.join(', '),\n result: { kind: 'atomic', label: '可降级拆分区域', overflow: 'split' },\n });\n\n // 兜底追加纯原生基础内置规则\n return [...customList, ...BASE_PRINT_RULES];\n}\n\nlet activePrintRules: PrintRule[] = buildPrintRules();\n\n/**\n * 全局统一配置打印规则(业务层通过此处注册各自技术栈/组件库的选择器)\n */\nexport function configurePrint(config: PrintRuleConfig): void {\n activePrintRules = buildPrintRules(config);\n}\n\n/**\n * 获取当前全局生效的打印规则列表\n */\nexport function getPrintRules(): readonly PrintRule[] {\n return activePrintRules;\n}\n\n/**\n * 重置全局规则为原生基础规则\n */\nexport function resetPrintRules(): void {\n activePrintRules = buildPrintRules();\n}\n\n/**\n * 对节点进行分类匹配,首个匹配的选择器生效\n */\nexport function classifyPrintNode(\n node: ClassifiableNode,\n rules: readonly PrintRule[] = getPrintRules()\n): ElementRule {\n if (node.nodeType === TEXT_NODE_TYPE) {\n return node.textContent?.trim() ? { kind: 'text' } : { kind: 'ignore' };\n }\n if (node.nodeType !== ELEMENT_NODE_TYPE || typeof node.matches !== 'function') {\n return { kind: 'ignore' };\n }\n return rules.find(rule => node.matches!(rule.selector))?.result || { kind: 'container' };\n}\n\nexport function resolveAtomicOverflow(\n rule: Extract<ElementRule, { kind: 'atomic' }>,\n height: number,\n capacity: number,\n customLabel?: string | null\n): 'protect' | 'descend' {\n if (height <= capacity) return 'protect';\n if (rule.overflow === 'split') return 'descend';\n const label = customLabel || rule.label;\n throw new Error(\n `不可拆分区域「${label}」高 ${Math.ceil(height)}px,超过正文可用高度 ${Math.floor(capacity)}px,请缩小该区域或增大页面高度`\n );\n}\n","export type VisitAction = 'descend' | 'skip';\n\n/** Depth-first DOM traversal. An explicit stack avoids JS call-stack limits. */\nexport function walkPrintTree(root: Node, visit: (node: Node) => VisitAction) {\n const pending: Node[] = [];\n const pushChildren = (node: Node) => {\n for (let i = node.childNodes.length - 1; i >= 0; i--) pending.push(node.childNodes[i]);\n };\n pushChildren(root);\n while (pending.length) {\n const node = pending.pop()!;\n if (visit(node) === 'descend') pushChildren(node);\n }\n}\n","import { classifyPrintNode } from '../../core/rules/print-rules';\nimport { Interval } from '../../core/types';\nimport { walkPrintTree } from './traversal';\n\nexport function createTextMeasurer(rootTop: number, collapse: (y: number) => number = y => y) {\n const lineHeights = new WeakMap<Element, number>();\n const range = document.createRange();\n let characters = 0;\n return (node: Node): Interval[] => {\n characters += node.textContent?.length || 0;\n if (characters > 200000) throw new Error('文本超过 200,000 字符限制,请拆分导出');\n const parent = node.parentElement;\n if (parent && !lineHeights.has(parent)) {\n const win = parent.ownerDocument?.defaultView || window;\n const lh = win.getComputedStyle ? win.getComputedStyle(parent).lineHeight : window.getComputedStyle(parent).lineHeight;\n lineHeights.set(parent, parseFloat(lh));\n }\n const lineHeight = parent ? lineHeights.get(parent)! : NaN;\n range.selectNodeContents(node);\n const rects = range.getClientRects ? Array.from(range.getClientRects()) : [];\n return rects\n .filter(rect => rect.width > 0 && rect.height > 0)\n .map(rect => {\n // Existing leading approximation is retained here, isolated from element\n // rules. It is not a complete CSS line-box reconstruction for mixed fonts.\n const leading = Number.isFinite(lineHeight) ? Math.max(0, lineHeight - rect.height) / 2 : 0;\n return { top: collapse(rect.top - rootTop - leading), bottom: collapse(rect.bottom - rootTop + leading) };\n });\n };\n}\n\n/** Re-measure visible source text for preview/snapshot consistency checks. */\nexport function measureTextLines(root: HTMLElement): Interval[] {\n const measure = createTextMeasurer(root.getBoundingClientRect().top);\n const lines: Interval[] = [];\n walkPrintTree(root, node => {\n const rule = classifyPrintNode(node);\n if (rule.kind === 'ignore') return 'skip';\n if (rule.kind === 'text') {\n lines.push(...measure(node));\n return 'skip';\n }\n return 'descend';\n });\n return lines;\n}\n","import {\n classifyPrintNode,\n DEFAULT_PRINT_RULES,\n resolveAtomicOverflow,\n} from '../../core/rules/print-rules';\nimport { DocumentMeasurement, Interval, PrintRule } from '../../core/types';\nimport { createTextMeasurer } from './text-range';\nimport { walkPrintTree } from './traversal';\n\nexport function readRootHeight(root: HTMLElement): number {\n const height = Math.max(root.getBoundingClientRect().height, root.scrollHeight);\n if (height <= 0 || height > 200000) {\n throw new Error('打印区域为空或超过 200,000px 高度限制');\n }\n return height;\n}\n\n/** Read DOM geometry once; atomic subtrees do not need redundant text measurement. */\nexport function measureDocument(\n root: HTMLElement,\n capacity: number,\n rules: readonly PrintRule[] = DEFAULT_PRINT_RULES\n): Required<DocumentMeasurement> {\n const bounds = root.getBoundingClientRect();\n // Coordinates always belong to this DOM. The print snapshot removes ignored\n // subtrees before measuring; live annotations retain the visible page layout.\n const height = readRootHeight(root);\n const ranges: Interval[] = [];\n const text = createTextMeasurer(bounds.top);\n const stats = { visitedNodes: 0, atomicElements: 0, textNodes: 0, textFragments: 0 };\n const rootRule = classifyPrintNode(root, rules);\n if (rootRule.kind === 'ignore') throw new Error('打印区域已被 ignore 规则排除,请选择其他区域');\n if (rootRule.kind === 'atomic' && resolveAtomicOverflow(rootRule, height, capacity,\n root.getAttribute('data-print-label') || root.getAttribute('data-pdf-label') || root.getAttribute('alt')) === 'protect') {\n return { height, ranges: [{ top: 0, bottom: height }], stats: { ...stats, visitedNodes: 1, atomicElements: 1 } };\n }\n const add = (interval: Interval) => {\n const top = Math.max(0, interval.top);\n const bottom = Math.min(height, interval.bottom);\n if (bottom > top) ranges.push({ top, bottom });\n };\n walkPrintTree(root, node => {\n stats.visitedNodes++;\n const rule = classifyPrintNode(node, rules);\n if (rule.kind === 'ignore') return 'skip';\n if (rule.kind === 'container') return 'descend';\n if (rule.kind === 'text') {\n const fragments = text(node);\n stats.textNodes++;\n stats.textFragments += fragments.length;\n fragments.forEach(add);\n return 'skip';\n }\n const element = node as Element;\n const rect = element.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return 'skip';\n const customLabel = element.getAttribute('data-print-label') || element.getAttribute('data-pdf-label') || element.getAttribute('alt');\n if (resolveAtomicOverflow(rule, rect.height, capacity, customLabel) === 'descend') {\n return 'descend';\n }\n stats.atomicElements++;\n add({ top: rect.top - bounds.top, bottom: rect.bottom - bounds.top });\n return 'skip';\n });\n return { height, ranges, stats };\n}\n","export function checkCancelled(signal?: AbortSignal) {\n if (signal?.aborted) throw new Error('导出已取消');\n}\n","import { checkCancelled } from '../../application/cancellation';\nimport { classifyPrintNode, getPrintRules } from '../../core/rules/print-rules';\nimport { PrintRule } from '../../core/types';\n\nasync function settleLayout(signal?: AbortSignal) {\n // Font/image readiness resolves before the next browser layout pass. Timers also\n // settle when the tab is backgrounded, unlike an unbounded requestAnimationFrame.\n for (let i = 0; i < 2; i++) {\n checkCancelled(signal);\n await new Promise(resolve => setTimeout(resolve, 16));\n }\n checkCancelled(signal);\n}\n\nexport async function waitForResources(host: HTMLElement, signal?: AbortSignal, rules: readonly PrintRule[] = getPrintRules()) {\n checkCancelled(signal);\n let timeout: ReturnType<typeof setTimeout>;\n let abort = () => {};\n const guard = new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('字体或图片加载超时,请稍后重试')), 15000);\n abort = () => reject(new Error('导出已取消'));\n signal?.addEventListener('abort', abort, { once: true });\n });\n try {\n await Promise.race([guard, (async () => {\n await Promise.all([\n host.ownerDocument.fonts?.ready,\n ...[...(host.tagName === 'IMG' ? [host as HTMLImageElement] : []), ...Array.from(host.querySelectorAll('img'))].filter(img => {\n // Source readiness must not wait on explicitly excluded resources.\n for (let node: Element | null = img; node; node = node.parentElement) {\n if (classifyPrintNode(node, rules).kind === 'ignore') return false;\n if (node === host) break;\n }\n return true;\n }).map(async img => {\n try { await img.decode(); }\n catch { throw new Error(`图片加载失败:${img.alt || '未命名图片'}`); }\n if (!img.naturalWidth) throw new Error(`图片内容为空:${img.alt || '未命名图片'}`);\n }),\n ]);\n await settleLayout(signal);\n })()]);\n checkCancelled(signal);\n } finally {\n clearTimeout(timeout!);\n signal?.removeEventListener('abort', abort);\n }\n}\n","import { waitForResources } from '../resources/resource-loader';\nimport { classifyPrintNode, getPrintRules } from '../../core/rules/print-rules';\nimport { PrintRule } from '../../core/types';\n\n/** Freeze resolved CSS so moving the print root outside its original context does not change typography or layout. */\nexport function copyResolvedStyle(source: Element, target: HTMLElement | SVGElement) {\n const win = source.ownerDocument?.defaultView || (typeof window !== 'undefined' ? window : null);\n const computed = win?.getComputedStyle ? win.getComputedStyle(source) : null;\n if (!computed) return;\n\n for (let i = 0; i < computed.length; i++) {\n const property = computed.item(i);\n // Computed dimensions can be used values of an originally auto-sized box.\n // Freezing those values changes margin collapsing and table alignment.\n // Retain min/max constraints: unlike used auto dimensions these remain CSS\n // constraints and can come from ancestor-dependent component-library rules.\n if (/^(width|height|block-size|inline-size)$/.test(property)) {\n // Intrinsic media and tables must retain their rendered size when an ancestor\n // selector no longer matches in the detached snapshot. Generic flow boxes\n // keep auto sizing so margin collapse and table alignment remain unchanged.\n if (!/^(IMG|CANVAS|SVG|TABLE|COL|COLGROUP)$/.test(source.tagName.toUpperCase())) continue;\n }\n target.style.setProperty(property, computed.getPropertyValue(property), computed.getPropertyPriority(property));\n }\n target.style.animation = 'none';\n target.style.transition = 'none';\n}\n\n/**\n * Clone DOM element and freeze resolved CSS so rendering outside its original context\n * (e.g. inside detached print containers or preview widgets, or from an iframe) does not alter typography,\n * inherited line-heights, or layout dimensions.\n */\nexport function cloneWithResolvedStyles(source: HTMLElement, rules: readonly PrintRule[] = getPrintRules()): HTMLElement {\n const ownerDoc = typeof document !== 'undefined' ? document : source.ownerDocument;\n const target = (ownerDoc?.importNode ? ownerDoc.importNode(source, true) : source.cloneNode(true)) as HTMLElement;\n\n // Preserve form and canvas state that cloneNode/importNode does not copy.\n const sources = [source, ...Array.from(source.querySelectorAll('*'))];\n const targets = [target, ...Array.from(target.querySelectorAll('*'))];\n sources.forEach((node, i) => {\n const copy = targets[i];\n if (!copy || copy.nodeType !== 1) return;\n\n // Exclude before resource decoding and layout, including configured selectors.\n if (node !== source && classifyPrintNode(node, rules).kind === 'ignore') {\n copy.remove();\n return;\n }\n for (const attribute of Array.from(copy.attributes)) {\n if (/^on/i.test(attribute.name) || attribute.name === 'autofocus') copy.removeAttribute(attribute.name);\n }\n const tagName = (node.tagName || '').toLowerCase();\n if (tagName === 'input') {\n const srcInput = node as HTMLInputElement;\n const dstInput = copy as HTMLInputElement;\n dstInput.value = srcInput.value;\n dstInput.checked = srcInput.checked;\n } else if (tagName === 'textarea') {\n (copy as HTMLTextAreaElement).value = (node as HTMLTextAreaElement).value;\n } else if (tagName === 'select') {\n (copy as HTMLSelectElement).selectedIndex = (node as HTMLSelectElement).selectedIndex;\n } else if (tagName === 'canvas') {\n const canvasSource = node as HTMLCanvasElement;\n const canvasCopy = copy as HTMLCanvasElement;\n canvasCopy.width = canvasSource.width;\n canvasCopy.height = canvasSource.height;\n try {\n // Detect taint before html2canvas can silently omit an unreadable canvas.\n canvasSource.toDataURL();\n const context = canvasCopy.getContext('2d');\n if (!context) throw new Error('canvas context unavailable');\n context.drawImage(canvasSource, 0, 0);\n } catch {\n throw new Error('画布内容无法读取,请检查跨域图片或浏览器的画布支持');\n }\n } else if (tagName === 'img') {\n const imgCopy = copy as HTMLImageElement;\n imgCopy.loading = 'eager';\n imgCopy.src = (node as HTMLImageElement).currentSrc || (node as HTMLImageElement).src;\n imgCopy.removeAttribute('srcset');\n imgCopy.removeAttribute('sizes');\n // Fail during preparation when a remote image cannot be used by canvas.\n if (/^https?:/.test(imgCopy.src) && typeof window !== 'undefined') {\n try {\n if (new URL(imgCopy.src).origin !== window.location.origin) {\n imgCopy.crossOrigin = 'anonymous';\n }\n } catch {\n // ignore invalid URLs\n }\n }\n }\n\n if ((copy as any).style) {\n copyResolvedStyle(node, copy as HTMLElement);\n }\n });\n target.querySelectorAll('[data-print-debug], [data-print-ignore=\"true\"], [data-pdf-debug], [data-pdf-ignore=\"true\"]').forEach(node => node.remove());\n\n // The root's margins position it in the source page (including resolved auto\n // centering margins). A page slice supplies its own origin and paper margins;\n // carrying those external offsets into it shifts/crops the captured document.\n // Descendant margins remain frozen above to preserve the internal layout.\n target.style.margin = '0';\n target.style.setProperty('margin-inline', '0');\n target.style.setProperty('margin-block', '0');\n\n // Lock root target width to source element width so rendering outside original flow never shrink-wraps or alters line wrapping\n const sourceWidth = source.getBoundingClientRect().width;\n if (sourceWidth > 0) {\n target.style.width = `${sourceWidth}px`;\n target.style.maxWidth = 'none';\n target.style.boxSizing = 'border-box';\n }\n\n return target;\n}\n\n/** Owns detached print DOM; callers dispose it on every success/error path. */\nexport function createPrintSnapshot(width: number, rules: readonly PrintRule[] = getPrintRules()) {\n const host = document.createElement('div');\n host.setAttribute('data-print-snapshot', 'true');\n host.setAttribute('aria-hidden', 'true');\n host.setAttribute('inert', '');\n host.style.cssText = `position:absolute;left:-100000px;top:0;width:${width}px;pointer-events:none;background:white;`;\n const clone = (source: HTMLElement) => {\n const target = cloneWithResolvedStyles(source, rules);\n target.style.width = `${width}px`;\n target.style.maxWidth = 'none';\n target.style.boxSizing = 'border-box';\n host.appendChild(target);\n return target;\n };\n return {\n clone,\n mount: () => document.body.appendChild(host),\n ready: (signal?: AbortSignal) => waitForResources(host, signal),\n dispose: () => host.remove(),\n };\n}\n\n/** A preview is passive: preserve live form/canvas values without executing source handlers. */\nexport function serializePrintSnapshot(root: HTMLElement): string {\n const clone = root.cloneNode(true) as HTMLElement;\n let serializedRoot = clone;\n const sources = [root, ...Array.from(root.querySelectorAll('*'))];\n const targets = [clone, ...Array.from(clone.querySelectorAll('*'))];\n sources.forEach((source, index) => {\n const target = targets[index];\n for (const attribute of Array.from(target.attributes)) {\n if (/^on/i.test(attribute.name)) target.removeAttribute(attribute.name);\n }\n if (source instanceof HTMLCanvasElement) {\n const image = document.createElement('img');\n image.src = source.toDataURL('image/png');\n image.style.cssText = (target as HTMLElement).style.cssText;\n image.width = source.width;\n image.height = source.height;\n if (target === clone) serializedRoot = image;\n else target.replaceWith(image);\n } else if (source instanceof HTMLInputElement) {\n target.setAttribute('value', source.type === 'password' ? '' : source.value);\n target.toggleAttribute('checked', source.checked);\n } else if (source instanceof HTMLTextAreaElement) {\n target.textContent = source.value;\n } else if (source instanceof HTMLOptionElement) {\n target.toggleAttribute('selected', source.selected);\n }\n if (target.matches('a, button, input, textarea, select, [tabindex]')) target.setAttribute('tabindex', '-1');\n });\n return serializedRoot.outerHTML;\n}\n\n/** Isolate repeated preview IDs while preserving SVG paint servers and label references. */\nexport function namespacePreviewHtml(html: string, namespace: string): string {\n const ids = new Map<string, string>();\n html.replace(/\\sid=\"([^\"]+)\"/g, (_match, id: string) => { ids.set(id, `${namespace}-${id}`); return _match; });\n return html.replace(/(\\s(?:id|for|href|xlink:href|aria-labelledby|aria-describedby)=\"|url\\(#)([^\")]+)(\"|\\))/g,\n (match, start: string, value: string, end: string) => {\n const hash = value.startsWith('#');\n const parts = (hash ? value.slice(1) : value).split(' ').map(id => ids.get(id) || id).join(' ');\n return `${start}${hash ? '#' : ''}${parts}${end}`;\n });\n}\n","import html2canvas from 'html2canvas';\n\nconst MAX_PIXELS = 8_000_000;\n\n/** Owns bounded page canvases and their memory; independent of PDF composition. */\nexport function createPageCapture(width: number, signal?: AbortSignal) {\n const canvases = new Set<HTMLCanvasElement>();\n const release = (canvas: HTMLCanvasElement) => {\n canvas.width = 0;\n canvas.height = 0;\n canvases.delete(canvas);\n };\n return {\n async capture(element: HTMLElement, y: number, height: number) {\n if (signal?.aborted) throw new Error('导出已取消');\n const scale = Math.min(2, Math.sqrt(MAX_PIXELS / (Math.ceil(width) * Math.ceil(height))), 8192 / width, 8192 / height);\n if (!Number.isFinite(scale) || scale < 0.5) throw new Error('页面像素超限,请缩小打印区域宽度');\n const canvas = await html2canvas(element, {\n x: 0,\n y,\n width,\n height,\n scale,\n useCORS: true,\n allowTaint: false,\n backgroundColor: '#ffffff',\n logging: false,\n imageTimeout: 15000,\n ignoreElements: node => {\n if (node.hasAttribute('data-print-debug') || node.getAttribute('data-print-ignore') === 'true') return true;\n // html2canvas otherwise clones the entire document for EACH page,\n // including the original long article and every HTML preview copy.\n // Keep this snapshot, its ancestors and head resources only.\n if (node.tagName === 'HEAD' || node.closest('head')) return false;\n return node !== element && !node.contains(element) && !element.contains(node);\n },\n });\n canvases.add(canvas);\n if (signal?.aborted) throw new Error('导出已取消');\n if (!canvas.width || !canvas.height) throw new Error('截图为空,请检查打印区域');\n return canvas;\n },\n release,\n dispose: () => canvases.forEach(release),\n };\n}\n","export function formatPageNumber(pageIndex: number, totalPages: number, format?: 'slash' | 'chinese' | 'hyphen') {\n const current = pageIndex + 1;\n switch (format) {\n case 'chinese':\n return `第 ${current} 页 / 共 ${totalPages} 页`;\n case 'hyphen':\n return `- ${current} -`;\n case 'slash':\n default:\n return `${current} / ${totalPages}`;\n }\n}\n","import { formatPageNumber } from '../../output/page-number';\nimport { PageGeometry } from '../../core/geometry/page-geometry';\nimport { mmToPt } from '../../core/geometry/paper';\nimport { PrintSettings } from '../../core/types';\n\nexport interface PdfDocumentWriterOptions {\n geometry: PageGeometry;\n settings?: Partial<PrintSettings>;\n headerCanvas?: HTMLCanvasElement;\n footerCanvas?: HTMLCanvasElement;\n totalPages: number;\n}\n\nexport { formatPageNumber } from '../../output/page-number';\n\n/** Adapter around jsPDF for composing multi-page rendered slices, headers, footers and page numbers. */\nexport async function createPdfWriter({\n geometry,\n settings,\n headerCanvas,\n footerCanvas,\n totalPages,\n}: PdfDocumentWriterOptions) {\n const { jsPDF } = await import('jspdf');\n const { pageWidth, pageHeight, contentWidth, headerHeight, footerHeight, left, bodyTop, headerY, footerY, pageNumberY } =\n geometry;\n const orientation = pageWidth > pageHeight ? 'landscape' : 'portrait';\n const pdf = new jsPDF({ unit: 'pt', format: [pageWidth, pageHeight], orientation });\n const rightMarginPt = settings?.marginRightMm !== undefined ? mmToPt(settings.marginRightMm) : mmToPt(10);\n\n return {\n addPageSlice(pageIndex: number, canvas: HTMLCanvasElement, sliceHeightPt: number) {\n if (pageIndex > 0) pdf.addPage();\n pdf.addImage(canvas, 'PNG', left, bodyTop, contentWidth, sliceHeightPt, undefined, 'FAST');\n if (headerCanvas) {\n pdf.addImage(headerCanvas, 'PNG', left, headerY, contentWidth, headerHeight, 'print-header', 'FAST');\n }\n if (footerCanvas) {\n pdf.addImage(footerCanvas, 'PNG', left, footerY, contentWidth, footerHeight, 'print-footer', 'FAST');\n }\n\n const pageNoConfig = settings?.pageNumber;\n const showPageNumber = pageNoConfig ? pageNoConfig.enabled : true;\n if (showPageNumber) {\n pdf.setFontSize(9);\n pdf.setTextColor(120, 120, 120);\n const position = pageNoConfig?.position || 'bottom-right';\n const text = formatPageNumber(pageIndex, totalPages, pageNoConfig?.format);\n let x: number;\n let align: 'left' | 'center' | 'right';\n if (position === 'bottom-center' || position === 'top-center') {\n x = pageWidth / 2;\n align = 'center';\n } else {\n x = pageWidth - rightMarginPt;\n align = 'right';\n }\n const y = pageNumberY;\n if (pageNoConfig?.format === 'chinese') {\n // Built-in PDF fonts do not contain Chinese glyphs. Use the browser's\n // system font for this tiny label instead of exporting garbled text.\n const label = document.createElement('canvas');\n label.width = 640; label.height = 48;\n const context = label.getContext('2d');\n if (!context) throw new Error('浏览器无法渲染中文页码');\n context.font = '24px sans-serif';\n const width = Math.ceil(context.measureText(text).width);\n context.fillStyle = '#787878';\n context.fillText(text, 0, 34);\n const labelWidth = width * 9 / 24;\n const offset = align === 'center' ? labelWidth / 2 : labelWidth;\n pdf.addImage(label, 'PNG', x - offset, y - 12.75, 240, 18);\n label.width = 0; label.height = 0;\n } else pdf.text(text, x, y, { align });\n }\n },\n async finalize(filename: string, download = true) {\n const blob = pdf.output('blob');\n if (download) {\n await pdf.save(`${filename.replace(/\\.pdf$/i, '') || 'document'}.pdf`, { returnPromise: true });\n }\n return blob;\n },\n };\n}\n","import { measureDocument } from '../adapters/dom/measurement';\nimport { createPrintSnapshot } from '../adapters/dom/snapshot';\nimport { waitForResources } from '../adapters/resources/resource-loader';\nimport { calculateGeometry, PageGeometry } from '../core/geometry/page-geometry';\nimport { DEFAULT_SETTINGS, resolvePaper } from '../core/geometry/paper';\nimport { paginate } from '../core/pagination/paginator';\nimport { buildPrintRules, getPrintRules } from '../core/rules/print-rules';\nimport {\n DeclarativeHeaderFooterConfig,\n MeasurementStats,\n Orientation,\n PageSlice,\n PrintRule,\n PrintRuleConfig,\n PrintSettings,\n} from '../core/types';\nimport { checkCancelled } from './cancellation';\n\nexport type { Orientation } from '../core/types';\n\nexport function createDeclarativeElement(\n config: DeclarativeHeaderFooterConfig,\n type: 'header' | 'footer',\n width: number\n): HTMLElement {\n const el = document.createElement('div');\n el.className = `print-declarative-${type}`;\n el.style.width = `${width}px`;\n el.style.boxSizing = 'border-box';\n el.style.padding = type === 'header' ? '8px 0 6px 0' : '6px 0 8px 0';\n el.style.textAlign = config.align || 'center';\n el.style.fontSize = type === 'header' ? '12px' : '11px';\n el.style.color = type === 'header' ? '#334155' : '#64748b';\n el.style.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif';\n el.style.lineHeight = '1.4';\n if (config.showDivider) {\n if (type === 'header') {\n el.style.borderBottom = '1px solid #cbd5e1';\n } else {\n el.style.borderTop = '1px solid #cbd5e1';\n }\n }\n el.textContent = config.text || '';\n return el;\n}\n\nexport interface PaginationPipelineOptions {\n root: HTMLElement;\n capacity: number;\n maxPages: number;\n rules?: readonly PrintRule[];\n ruleConfig?: PrintRuleConfig;\n}\n\nexport interface LayoutOptions {\n element: HTMLElement | null;\n header?: HTMLElement | null;\n footer?: HTMLElement | null;\n orientation?: Orientation;\n settings?: Partial<PrintSettings>;\n signal?: AbortSignal;\n maxPages?: number;\n rules?: readonly PrintRule[];\n ruleConfig?: PrintRuleConfig;\n}\n\nexport interface PreparedLayout extends PageGeometry {\n root: HTMLElement;\n header?: HTMLElement;\n footer?: HTMLElement;\n width: number;\n pages: PageSlice[];\n stats?: MeasurementStats;\n timing: {\n measurementMs: number;\n paginationMs: number;\n };\n cleanup: () => void;\n}\n\nconst activeRoots = new WeakSet<HTMLElement>();\n\n/** DOM measurement adapter → measured intervals → pure core paginator. */\nexport function planDocument({ root, capacity, maxPages, rules, ruleConfig }: PaginationPipelineOptions) {\n const started = performance.now();\n const resolvedRules = rules || (ruleConfig ? buildPrintRules(ruleConfig) : getPrintRules());\n const measurement = measureDocument(root, capacity, resolvedRules);\n const measured = performance.now();\n const pages = paginate(measurement.height, capacity, measurement.ranges, maxPages);\n return {\n pages,\n stats: measurement.stats,\n timing: {\n measurementMs: measured - started,\n paginationMs: performance.now() - measured,\n },\n };\n}\n\n/**\n * Safely verify whether a node is a printable DOM element,\n * including elements from an iframe or different window realm.\n */\nexport function isPrintableElement(node: unknown): node is HTMLElement {\n if (!node || typeof node !== 'object') return false;\n const el = node as any;\n if (el.nodeType !== 1) return false;\n const win = el.ownerDocument?.defaultView;\n const isElement =\n (win && typeof win.HTMLElement === 'function' && el instanceof win.HTMLElement) ||\n (typeof HTMLElement !== 'undefined' && el instanceof HTMLElement) ||\n (typeof el.getBoundingClientRect === 'function' && typeof el.cloneNode === 'function');\n if (!isElement) return false;\n return Boolean(el.isConnected ?? el.ownerDocument?.contains?.(el));\n}\n\n/** If an iframe element is passed, automatically resolve its inner document body or main report content */\nexport function resolvePrintElement(target: unknown): HTMLElement | null {\n if (!isPrintableElement(target)) return null;\n if (target.tagName?.toLowerCase() === 'iframe') {\n const iframe = target as HTMLIFrameElement;\n let doc: Document | null | undefined;\n try {\n doc = iframe.contentDocument || iframe.contentWindow?.document;\n } catch {\n throw new Error('无法读取跨域 iframe,请在嵌入系统内接入打印工具或使用其导出接口');\n }\n if (!doc?.body || doc.readyState === 'loading' || (doc.URL === 'about:blank' && Boolean(iframe.getAttribute('src')))) {\n throw new Error('iframe 内容尚未就绪,请等待加载完成后重试');\n }\n const content = (doc.getElementById('iframe-report-content') as HTMLElement) || doc.body;\n if (!isPrintableElement(content) || (!content.childElementCount && !content.textContent?.trim())) {\n throw new Error('iframe 中没有可打印的业务内容');\n }\n return content;\n }\n return target;\n}\n\n/** Pipeline orchestration: snapshot & resource readiness → page geometry → pagination planning. */\nexport async function prepareLayout(options: LayoutOptions): Promise<PreparedLayout> {\n const { header, footer, signal, orientation = 'portrait' } = options;\n const maxPages = options.maxPages ?? 100;\n\n const printElement = resolvePrintElement(options.element);\n if (!printElement) {\n throw new Error('找不到有效的打印区域');\n }\n if (!['portrait', 'landscape'].includes(orientation)) {\n throw new Error('纸张方向必须为 portrait 或 landscape');\n }\n const paper = resolvePaper({ ...DEFAULT_SETTINGS, orientation, ...(options.settings || {}) });\n if (activeRoots.has(printElement)) {\n throw new Error('该区域正在导出,请勿重复提交');\n }\n let width = printElement.getBoundingClientRect().width;\n if (!Number.isFinite(width) || width <= 0) {\n throw new Error('打印区域宽度为零,请先显示内容');\n }\n checkCancelled(signal);\n activeRoots.add(printElement);\n const rules = options.rules || (options.ruleConfig ? buildPrintRules(options.ruleConfig) : getPrintRules());\n let snapshot: ReturnType<typeof createPrintSnapshot> | undefined;\n const cleanup = () => {\n snapshot?.dispose();\n activeRoots.delete(printElement);\n };\n try {\n // Readiness must precede style freezing: otherwise an image still loading\n // can have its temporary 0px height frozen permanently into the snapshot.\n await waitForResources(printElement, signal, rules);\n width = printElement.getBoundingClientRect().width;\n if (!Number.isFinite(width) || width <= 0) throw new Error('打印区域宽度为零,请先显示内容');\n snapshot = createPrintSnapshot(width, rules);\n const root = snapshot.clone(printElement);\n\n let headerClone: HTMLElement | undefined;\n if (header && isPrintableElement(header)) {\n headerClone = snapshot.clone(header);\n } else if (options.settings?.header?.enabled && options.settings.header.text) {\n const declHeader = createDeclarativeElement(options.settings.header, 'header', width);\n headerClone = snapshot.clone(declHeader);\n }\n\n let footerClone: HTMLElement | undefined;\n if (footer && isPrintableElement(footer)) {\n footerClone = snapshot.clone(footer);\n } else if (options.settings?.footer?.enabled && options.settings.footer.text) {\n const declFooter = createDeclarativeElement(options.settings.footer, 'footer', width);\n footerClone = snapshot.clone(declFooter);\n }\n\n snapshot.mount();\n await snapshot.ready(signal);\n\n checkCancelled(signal);\n const pageNumber = options.settings?.pageNumber ?? true;\n const geometry = calculateGeometry(\n paper,\n width,\n headerClone?.getBoundingClientRect().height,\n footerClone?.getBoundingClientRect().height,\n pageNumber\n );\n const { pages, stats, timing } = planDocument({\n root,\n capacity: geometry.capacity,\n maxPages,\n rules,\n });\n return {\n ...geometry,\n root,\n header: headerClone,\n footer: footerClone,\n width,\n pages,\n stats,\n timing,\n cleanup,\n };\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n","const crcTable = Array.from({ length: 256 }, (_, index) => {\n let value = index;\n for (let bit = 0; bit < 8; bit++) value = (value >>> 1) ^ (0xedb88320 & -(value & 1));\n return value >>> 0;\n});\n\n/** ZIP STORE: PNG is already compressed. Keeping entries as Blobs avoids copying image buffers. */\nexport function createZipArchive(entries: { name: string; data: Uint8Array }[]): Blob {\n if (entries.length > 65535) throw new Error('图片页数超出 ZIP 限制');\n const parts: BlobPart[] = [], directory: BlobPart[] = [];\n let offset = 0, directorySize = 0;\n for (const { name, data } of entries) {\n // Output names are generated ASCII page numbers, independent of document titles.\n const filename = Uint8Array.from(name, c => c.charCodeAt(0));\n let crc = 0xffffffff;\n for (let i = 0; i < data.length; i++) crc = (crc >>> 8) ^ crcTable[(crc ^ data[i]) & 255];\n crc = (crc ^ 0xffffffff) >>> 0;\n if (offset + data.length + filename.length + 30 > 0xffffffff) throw new Error('图片包超过 4GB,请分批导出');\n const local = new Uint8Array(30 + filename.length), lv = new DataView(local.buffer);\n lv.setUint32(0, 0x04034b50, true); lv.setUint16(4, 20, true);\n lv.setUint16(12, 33, true); // 1980-01-01, the first DOS date.\n lv.setUint32(14, crc, true); lv.setUint32(18, data.length, true); lv.setUint32(22, data.length, true);\n lv.setUint16(26, filename.length, true); local.set(filename, 30);\n const central = new Uint8Array(46 + filename.length), cv = new DataView(central.buffer);\n cv.setUint32(0, 0x02014b50, true); cv.setUint16(4, 20, true); cv.setUint16(6, 20, true);\n cv.setUint16(14, 33, true); cv.setUint32(16, crc, true);\n cv.setUint32(20, data.length, true); cv.setUint32(24, data.length, true);\n cv.setUint16(28, filename.length, true); cv.setUint32(42, offset, true); central.set(filename, 46);\n parts.push(local, data); directory.push(central);\n offset += local.length + data.length; directorySize += central.length;\n }\n if (offset + directorySize + 22 > 0xffffffff) throw new Error('图片包超过 4GB,请分批导出');\n const end = new Uint8Array(22), ev = new DataView(end.buffer);\n ev.setUint32(0, 0x06054b50, true); ev.setUint16(8, entries.length, true); ev.setUint16(10, entries.length, true);\n ev.setUint32(12, directorySize, true); ev.setUint32(16, offset, true);\n return new Blob([...parts, ...directory, end], { type: 'application/zip' });\n}\n","import { checkCancelled } from '../application/cancellation';\nimport { mmToPt } from '../core/geometry/paper';\nimport { formatPageNumber } from './page-number';\nimport { OutputWriter, OutputWriterOptions } from './types';\nimport { createZipArchive } from './zip';\n\nfunction encodePng(canvas: HTMLCanvasElement): Promise<Blob> {\n return new Promise((resolve, reject) => canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('图片编码失败,请重试导出')), 'image/png'));\n}\nfunction readBlob(blob: Blob): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(new Uint8Array(reader.result as ArrayBuffer));\n reader.onerror = () => reject(new Error('图片读取失败,请重试导出'));\n reader.readAsArrayBuffer(blob);\n });\n}\n\n/** Compose full paper pages, encode each immediately, and release its canvas before the next page. */\nexport function createImageWriter({ geometry: g, settings, headerCanvas, footerCanvas, totalPages, signal }: OutputWriterOptions): OutputWriter {\n const entries: { name: string; data: Uint8Array }[] = [];\n return {\n async addPageSlice(index, body, heightPt) {\n checkCancelled(signal);\n const sheet = document.createElement('canvas');\n // Match capture density where possible, while bounding full-paper allocations.\n const density = Math.min(body.width / g.contentWidth, Math.sqrt(8_000_000 / (g.pageWidth * g.pageHeight)), 8192 / g.pageWidth, 8192 / g.pageHeight);\n sheet.width = Math.ceil(g.pageWidth * density); sheet.height = Math.ceil(g.pageHeight * density);\n try {\n const ctx = sheet.getContext('2d');\n if (!ctx) throw new Error('浏览器无法生成分页图片');\n ctx.scale(density, density);\n ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, g.pageWidth, g.pageHeight);\n ctx.drawImage(body, g.left, g.bodyTop, g.contentWidth, heightPt);\n if (headerCanvas) ctx.drawImage(headerCanvas, g.left, g.headerY, g.contentWidth, g.headerHeight);\n if (footerCanvas) ctx.drawImage(footerCanvas, g.left, g.footerY, g.contentWidth, g.footerHeight);\n if (settings?.pageNumber?.enabled !== false) {\n const center = settings?.pageNumber?.position?.endsWith('center');\n ctx.font = '9px sans-serif'; ctx.fillStyle = '#787878'; ctx.textAlign = center ? 'center' : 'right';\n ctx.fillText(formatPageNumber(index, totalPages, settings?.pageNumber?.format), center ? g.pageWidth / 2 : g.pageWidth - mmToPt(settings?.marginRightMm ?? 10), g.pageNumberY);\n }\n const data = await readBlob(await encodePng(sheet));\n checkCancelled(signal);\n entries.push({ name: `page-${String(index + 1).padStart(Math.max(3, String(totalPages).length), '0')}.png`, data });\n } finally { sheet.width = 0; sheet.height = 0; }\n },\n async finalize(filename, download = true) {\n checkCancelled(signal);\n const blob = createZipArchive(entries);\n checkCancelled(signal);\n if (download) {\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url; anchor.download = `${filename.replace(/\\.(pdf|zip|png)$/i, '') || 'document'}-pages.zip`;\n document.body.appendChild(anchor);\n try { anchor.click(); } finally { anchor.remove(); setTimeout(() => URL.revokeObjectURL(url), 60000); }\n }\n return blob;\n },\n dispose() { entries.length = 0; },\n };\n}\n","import { createPdfWriter } from '../adapters/pdf/jspdf-writer';\nimport { createImageWriter } from './image-writer';\nimport { OutputFormat, OutputWriter, OutputWriterOptions } from './types';\nexport * from './types';\n\nconst writerFactories: Record<OutputFormat, (options: OutputWriterOptions) => OutputWriter | Promise<OutputWriter>> = {\n pdf: createPdfWriter,\n png: createImageWriter,\n};\n\nexport function validateOutputFormat(format: OutputFormat): void {\n if (!Object.prototype.hasOwnProperty.call(writerFactories, format)) throw new Error(`不支持的输出格式:${format}`);\n}\n\nexport function createOutputWriter(format: OutputFormat, options: OutputWriterOptions): Promise<OutputWriter> | OutputWriter {\n validateOutputFormat(format);\n return writerFactories[format](options);\n}\n","import { createPageCapture } from '../adapters/canvas/page-capture';\nimport { measureDocument } from '../adapters/dom/measurement';\nimport { createOutputWriter, OutputFormat, OutputWriter, validateOutputFormat } from '../output';\nimport { validatePageBreaks } from '../core/pagination/paginator';\nimport { buildPrintRules, getPrintRules } from '../core/rules/print-rules';\nimport { Interval, MeasurementStats, PageSlice } from '../core/types';\nimport { checkCancelled } from './cancellation';\nimport { LayoutOptions, prepareLayout, resolvePrintElement } from './print-pipeline';\n\nexport interface ExportOptions extends LayoutOptions {\n filename: string;\n download?: boolean;\n onProgress?: (completed: number, total: number) => void;\n}\n\nexport interface DocumentExportOptions extends ExportOptions {\n format?: OutputFormat;\n}\n\nexport interface PreviewPaginationOptions extends Omit<LayoutOptions, 'element'> {\n contentElement: HTMLElement | null;\n}\n\nexport interface PrintInspectionResult {\n pageBreaks: number[];\n pages: PageSlice[];\n totalHeight: number;\n capacity: number;\n protectedRanges: Interval[];\n stats?: MeasurementStats;\n timing: {\n measurementMs: number;\n paginationMs: number;\n totalMs: number;\n };\n}\n\n/** Share snapshot, pagination and page capture across all output formats. */\nexport async function outputDocument({ format = 'pdf', filename, download = true, onProgress, ...options }: DocumentExportOptions) {\n validateOutputFormat(format);\n const started = performance.now();\n const layout = await prepareLayout(options);\n const { root, headerHeight, footerHeight, ratio, pages } = layout;\n const layoutMs = performance.now() - started;\n let renderer: ReturnType<typeof createPageCapture> | undefined;\n let writer: OutputWriter | undefined;\n try {\n renderer = createPageCapture(layout.width, options.signal);\n const { capture, release } = renderer;\n const headerCanvas = layout.header ? await capture(layout.header, 0, headerHeight / ratio) : undefined;\n const footerCanvas = layout.footer ? await capture(layout.footer, 0, footerHeight / ratio) : undefined;\n writer = await createOutputWriter(format, {\n signal: options.signal,\n geometry: layout,\n settings: options.settings,\n headerCanvas,\n footerCanvas,\n totalPages: pages.length,\n });\n onProgress?.(0, pages.length);\n for (let i = 0; i < pages.length; i++) {\n checkCancelled(options.signal);\n const page = pages[i];\n const canvas = await capture(root, page.start, page.end - page.start);\n try { await writer.addPageSlice(i, canvas, (page.end - page.start) * ratio); }\n finally { release(canvas); }\n onProgress?.(i + 1, pages.length);\n await new Promise(resolve => setTimeout(resolve, 0));\n }\n checkCancelled(options.signal);\n const blob = await writer.finalize(filename, download);\n return {\n blob,\n pages: pages.length,\n layoutMs,\n totalMs: performance.now() - started,\n bytes: blob.size,\n };\n } finally {\n writer?.dispose?.();\n renderer?.dispose();\n layout.cleanup();\n }\n}\n\n/** Backward-compatible PDF entry point. */\nexport function outputPDF(options: ExportOptions) {\n return outputDocument({ ...options, format: 'pdf' });\n}\n\n/** Run full snapshot measurement and pagination validation, returning structured diagnostics. */\nexport async function inspectPrintLayout({\n contentElement,\n ...options\n}: PreviewPaginationOptions): Promise<PrintInspectionResult> {\n const started = performance.now();\n const target = resolvePrintElement(contentElement);\n const layout = await prepareLayout({ element: target, ...options });\n try {\n const pageBreaks = layout.pages.map(page => page.start);\n const rules = options.rules || (options.ruleConfig ? buildPrintRules(options.ruleConfig) : getPrintRules());\n // Removing ignore nodes can reflow flex/grid and collapse margins. Comparing\n // those print coordinates with live source coordinates is invalid. Validate\n // against the actual snapshot used by both preview and export instead.\n const snapshotMeasurement = measureDocument(layout.root, layout.capacity, rules);\n validatePageBreaks(layout.pages, snapshotMeasurement.ranges);\n const result: PrintInspectionResult = {\n pageBreaks,\n pages: layout.pages,\n totalHeight: snapshotMeasurement.height,\n capacity: layout.capacity,\n protectedRanges: snapshotMeasurement.ranges,\n stats: layout.stats,\n timing: {\n measurementMs: layout.timing?.measurementMs ?? 0,\n paginationMs: layout.timing?.paginationMs ?? 0,\n totalMs: performance.now() - started,\n },\n };\n window.dispatchEvent(new CustomEvent('print-inspection', { detail: result }));\n // Existing integrations can migrate their listener without a breaking change.\n window.dispatchEvent(new CustomEvent('pdf-print-inspection', { detail: result }));\n return result;\n } finally {\n layout.cleanup();\n }\n}\n\n/** Uses the exact snapshot measurement and page planner used by PDF export, with coordinates relative to the prepared print snapshot. */\nexport async function calculatePagesArray(options: PreviewPaginationOptions) {\n const result = await inspectPrintLayout(options);\n return result.pageBreaks;\n}\n","import { walkPrintTree } from '../adapters/dom/traversal';\nimport { classifyPrintNode, getPrintRules } from '../core/rules/print-rules';\nimport { PrintRule } from '../core/types';\n\nexport interface ObservabilityStats {\n atomic: number;\n splittable: number;\n ignore: number;\n}\n\nconst restorers = new Map<HTMLElement, () => void>();\n\nexport function clearPageBreaks(owner?: Document | HTMLElement) {\n const scope = owner || document;\n scope.querySelectorAll('[data-print-debug]').forEach(node => node.remove());\n for (const [root, restore] of Array.from(restorers)) {\n if (!owner || owner === root || (owner.nodeType === 9 && root.ownerDocument === owner)) {\n restore();\n restorers.delete(root);\n }\n }\n}\n\nexport function visualizePageBreaks(\n pages: number[],\n element: HTMLElement,\n rules: readonly PrintRule[] = getPrintRules()\n): ObservabilityStats {\n clearPageBreaks(element);\n\n const stats: ObservabilityStats = {\n atomic: 0,\n splittable: 0,\n ignore: 0,\n };\n\n const win = element.ownerDocument?.defaultView || (typeof window !== 'undefined' ? window : null);\n const computed = win?.getComputedStyle ? win.getComputedStyle(element) : null;\n\n if (computed && computed.position === 'static') {\n const position = element.style.getPropertyValue('position');\n const priority = element.style.getPropertyPriority('position');\n element.style.position = 'relative';\n restorers.set(element, () => {\n if (position) element.style.setProperty('position', position, priority);\n else element.style.removeProperty('position');\n });\n }\n\n const rootRect = element.getBoundingClientRect();\n const borderTop = computed ? (parseFloat(computed.borderTopWidth) || 0) : 0;\n const borderLeft = computed ? (parseFloat(computed.borderLeftWidth) || 0) : 0;\n\n // 扫描当前打印区域内各节点,严格按照 3 种元素语义分类:\n // 1. ignore (不打印)\n // 2. atomic (不可分割最小原子项)\n // 3. splittable (可分割流式项)\n // 分类结果必须与 measureDocument 保持一致;否则会出现\"标成可分割但实际没被切开\"的错位。\n walkPrintTree(element, node => {\n if (node.nodeType !== 1) return 'skip';\n const el = node as HTMLElement;\n if (el.hasAttribute('data-print-debug')) return 'skip';\n\n const rule = classifyPrintNode(el, rules);\n\n // 1. ignore (不打印:交互控件 / 分页器 / 隐藏元素)\n if (rule.kind === 'ignore') {\n stats.ignore++;\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n element.appendChild(\n createOverlay({\n left: rect.left - rootRect.left - borderLeft,\n top: rect.top - rootRect.top - borderTop,\n width: rect.width,\n height: rect.height,\n borderColor: '#94a3b8',\n borderStyle: 'dashed',\n backgroundColor: 'rgba(148, 163, 184, 0.08)',\n badgeText: 'ignore',\n badgeBg: '#64748b',\n badgePosition: 'left',\n })\n );\n }\n return 'skip';\n }\n\n const rect = el.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return 'skip';\n\n // 2. atomic (不可分割原子项:表格行、标题、图片媒体、卡片、业务注册原子项)\n if (rule.kind === 'atomic') {\n stats.atomic++;\n element.appendChild(\n createOverlay({\n left: rect.left - rootRect.left - borderLeft,\n top: rect.top - rootRect.top - borderTop,\n width: rect.width,\n height: rect.height,\n borderColor: '#ef4444',\n borderStyle: 'solid',\n backgroundColor: 'rgba(239, 68, 68, 0.05)',\n badgeText: 'atomic',\n badgeBg: '#ef4444',\n badgePosition: 'right',\n })\n );\n return 'skip';\n }\n\n // 行内元素(b / code / 行内公式)不单独成框,避免把一行文字里的片段标成\"区域\"\n if (isInlineBox(el, win)) return 'skip';\n\n // 3. splittable (可分割流式项:真正拥有正文文本的块,允许被物理分页线切断)\n const explicitSplit = el.matches(SPLIT_CONTAINER_SELECTOR);\n const ownsFlowingText = hasOwnText(el);\n if (explicitSplit || ownsFlowingText) {\n stats.splittable++;\n element.appendChild(\n createOverlay({\n left: rect.left - rootRect.left - borderLeft,\n top: rect.top - rootRect.top - borderTop,\n width: rect.width,\n height: rect.height,\n borderColor: '#3b82f6',\n borderStyle: 'dashed',\n backgroundColor: 'rgba(59, 130, 246, 0.04)',\n badgeText: 'splittable',\n badgeBg: '#3b82f6',\n badgePosition: 'right',\n })\n );\n // 显式声明的可分割容器继续下钻,让内部的原子子项照常标红\n return explicitSplit ? 'descend' : 'skip';\n }\n\n // 本身没有正文的容器(例如只包了一张图的 <p>)继续下钻,\n // 让真正的媒体子孙节点按 atomic 标红,而不是把整段标成 splittable。\n return 'descend';\n });\n\n // 绘制分页切割线与 page-break 指示标签(使用高辨识度紫色,避免与 atomic 红色混淆)\n pages.slice(1).forEach((breakY, index) => {\n const lineY = breakY - borderTop;\n const lineContainer = element.ownerDocument.createElement('div');\n lineContainer.setAttribute('data-print-debug', 'true');\n lineContainer.style.cssText = `\n position: absolute;\n left: 0;\n top: ${lineY}px;\n width: 100%;\n height: 0;\n border-top: 2px dashed #7c3aed;\n z-index: ${MARKER_LAYER.line};\n pointer-events: none;\n box-sizing: border-box;\n `;\n\n const pill = element.ownerDocument.createElement('span');\n pill.textContent = `✂️ page-break: ${Math.round(breakY)}px (p.${index + 1} ➔ p.${index + 2})`;\n pill.style.cssText = `\n position: absolute;\n right: 16px;\n top: -11px;\n background: #7c3aed;\n color: #fff;\n font-size: 11px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n line-height: 1;\n padding: 3px 8px;\n border-radius: 10px;\n font-weight: 600;\n letter-spacing: 0.2px;\n box-shadow: 0 1px 4px rgba(124, 58, 237, 0.35);\n white-space: nowrap;\n `;\n\n lineContainer.appendChild(pill);\n element.appendChild(lineContainer);\n });\n\n return stats;\n}\n\nconst SPLIT_CONTAINER_SELECTOR =\n '[data-print-splittable=\"true\"], .print-splittable, [data-print-break=\"split\"], .print-force-split, [data-pdf-splittable=\"true\"], .pdf-splittable, [data-pdf-break=\"split\"], .pdf-force-split';\n\n/**\n * 标记层必须留在页面内容与站点外壳之间:\n * 打印根节点不会创建独立层叠上下文,若这里用 900+ 的 z-index,\n * 标记会盖住吸顶的工具条(z-index 20)与站点导航(z-index 100)。\n * 只要盖过文档正文即可,所以统一用一个很小的区间。\n */\nconst MARKER_LAYER = { box: 2, badge: 3, line: 4 } as const;\n\n/** 行内语义标签:即使是 flex/grid 子项被 blockify,也不该被当成一块独立可分割区域 */\nconst INLINE_TAGS = new Set([\n 'SPAN', 'B', 'STRONG', 'EM', 'I', 'CODE', 'A', 'SMALL', 'SUP', 'SUB', 'MARK',\n 'ABBR', 'CITE', 'Q', 'TIME', 'U', 'S', 'KBD', 'SAMP', 'VAR', 'BR',\n]);\n\n/** 只认元素自己的文本节点:`<p><img></p>` 这类媒体包装段落本身没有正文,不该算可分割正文流 */\nfunction hasOwnText(el: HTMLElement): boolean {\n for (let i = 0; i < el.childNodes.length; i++) {\n const child = el.childNodes[i];\n if (child.nodeType === 3 && child.textContent?.trim()) return true;\n }\n return false;\n}\n\nfunction isInlineBox(el: HTMLElement, win: Window | null): boolean {\n if (INLINE_TAGS.has(el.tagName)) return true;\n if (!win?.getComputedStyle) return false;\n return win.getComputedStyle(el).display.startsWith('inline');\n}\n\nfunction createOverlay(opts: {\n left: number;\n top: number;\n width: number;\n height: number;\n borderColor: string;\n borderStyle: 'solid' | 'dashed';\n backgroundColor: string;\n badgeText: string;\n badgeBg: string;\n badgePosition?: 'left' | 'right';\n}): HTMLElement {\n const box = document.createElement('div');\n box.setAttribute('data-print-debug', 'true');\n box.style.cssText = `\n position: absolute;\n left: ${opts.left}px;\n top: ${opts.top}px;\n width: ${opts.width}px;\n height: ${opts.height}px;\n border: 1.5px ${opts.borderStyle} ${opts.borderColor};\n background: ${opts.backgroundColor};\n box-sizing: border-box;\n z-index: ${MARKER_LAYER.box};\n pointer-events: none;\n border-radius: 2px;\n `;\n\n const badge = document.createElement('span');\n badge.textContent = opts.badgeText;\n const isRight = opts.badgePosition === 'right';\n\n // 贴元素内部角隅放置(默认右上),确保在元素自身内部高亮,绝不跨界遮挡上方元素文字\n const badgeTop = '2px';\n const badgeSide = isRight ? 'right: 4px;' : 'left: 4px;';\n\n badge.style.cssText = `\n position: absolute;\n ${badgeSide}\n top: ${badgeTop};\n background: ${opts.badgeBg};\n color: #ffffff;\n font-size: 9px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-weight: 600;\n line-height: 1;\n padding: 1.5px 5px;\n border-radius: 3px;\n white-space: nowrap;\n box-shadow: 0 1px 2px rgba(0,0,0,0.18);\n z-index: ${MARKER_LAYER.badge};\n opacity: 0.95;\n letter-spacing: 0.2px;\n `;\n\n box.appendChild(badge);\n return box;\n}\n"],"names":["PT_PER_MM","MM_PER_PX","PX_PER_MM","pxToMm","px","IMAGE_PAPER_SIZES","IMAGE_PAPERS","isImagePaper","paper","getPresetUnit","PAPER_SIZES","key","preset","PAPER_PRESETS","DEFAULT_SETTINGS","getPresetDimensions","orientation","unit","widthMm","heightMm","short","long","marginTopMm","marginRightMm","marginBottomMm","marginLeftMm","mmToPt","mm","resolvePaper","settings","size","value","margins","a","b","UNIT_FIELDS","convertFields","factor","next","field","calculateGeometry","width","headerPx","footerPx","pageNumber","pageWidth","pageHeight","hasPageNumber","numberAtTop","_a","topReserve","bottomReserve","contentWidth","ratio","headerHeight","footerHeight","bodyTop","footerY","capacity","paginate","height","protectedRanges","maxPages","ranges","sorted","range","previous","pages","start","cursor","end","validatePageBreaks","tolerance","intersections","page","TEXT_NODE_TYPE","ELEMENT_NODE_TYPE","PRINT_ATTRIBUTES","PRINT_CLASSES","PDF_PRINT_ATTRIBUTES","PDF_PRINT_CLASSES","BASE_PRINT_RULES","DEFAULT_PRINT_RULES","buildPrintRules","config","customList","_b","splittableSelectors","atomicSelectors","_c","activePrintRules","configurePrint","getPrintRules","resetPrintRules","classifyPrintNode","node","rules","rule","resolveAtomicOverflow","customLabel","label","walkPrintTree","root","visit","pending","pushChildren","createTextMeasurer","rootTop","collapse","y","lineHeights","characters","parent","win","lh","lineHeight","rect","leading","measureTextLines","measure","lines","readRootHeight","measureDocument","bounds","text","stats","rootRule","add","interval","top","bottom","fragments","element","checkCancelled","signal","settleLayout","i","resolve","waitForResources","host","timeout","abort","guard","_","reject","img","copyResolvedStyle","source","target","computed","property","cloneWithResolvedStyles","ownerDoc","sources","targets","copy","attribute","tagName","srcInput","dstInput","canvasSource","canvasCopy","context","imgCopy","sourceWidth","createPrintSnapshot","serializePrintSnapshot","clone","serializedRoot","index","image","namespacePreviewHtml","html","namespace","ids","_match","id","match","hash","parts","MAX_PIXELS","createPageCapture","canvases","release","canvas","scale","html2canvas","formatPageNumber","pageIndex","totalPages","format","current","createPdfWriter","geometry","headerCanvas","footerCanvas","jsPDF","left","headerY","pageNumberY","pdf","rightMarginPt","sliceHeightPt","pageNoConfig","position","x","align","labelWidth","offset","filename","download","blob","createDeclarativeElement","type","el","activeRoots","planDocument","ruleConfig","started","resolvedRules","measurement","measured","isPrintableElement","resolvePrintElement","iframe","doc","content","prepareLayout","options","header","footer","printElement","snapshot","cleanup","headerClone","declHeader","footerClone","_d","declFooter","_e","timing","error","crcTable","bit","createZipArchive","entries","directory","directorySize","name","data","c","crc","local","lv","central","cv","ev","encodePng","readBlob","reader","createImageWriter","g","body","heightPt","sheet","density","ctx","center","url","anchor","writerFactories","validateOutputFormat","createOutputWriter","outputDocument","onProgress","layout","layoutMs","renderer","writer","capture","outputPDF","inspectPrintLayout","contentElement","pageBreaks","snapshotMeasurement","result","calculatePagesArray","restorers","clearPageBreaks","owner","restore","visualizePageBreaks","priority","rootRect","borderTop","borderLeft","createOverlay","isInlineBox","explicitSplit","SPLIT_CONTAINER_SELECTOR","ownsFlowingText","hasOwnText","breakY","lineY","lineContainer","MARKER_LAYER","pill","INLINE_TAGS","child","opts","box","badge","isRight","badgeTop","badgeSide"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/lib/application/print-session.ts"],"sourcesContent":["import { createPageCapture } from '../adapters/canvas/page-capture';\nimport { composePageCanvas } from '../output/image-writer';\nimport { PrintSettings } from '../core/types';\nimport { checkCancelled } from './cancellation';\nimport { LayoutOptions, prepareLayout } from './print-pipeline';\nimport { DocumentExportOptions, exportPreparedLayout } from './print-service';\n\n/** A frozen document shared by preview, inspection and all output formats. */\nexport async function createPrintSession(options: LayoutOptions) {\n const lifetime = new AbortController();\n const forwardAbort = () => lifetime.abort();\n options.signal?.addEventListener('abort', forwardAbort, { once: true });\n if (options.signal?.aborted) lifetime.abort();\n const started = performance.now();\n let layout;\n try { layout = await prepareLayout({ ...options, signal: lifetime.signal }); }\n catch (error) { options.signal?.removeEventListener('abort', forwardAbort); throw error; }\n const renderer = createPageCapture(layout.width, lifetime.signal);\n const settings: Partial<PrintSettings> | undefined = options.settings ? JSON.parse(JSON.stringify(options.settings)) : undefined;\n let disposed = false;\n let busy = false;\n const assertLive = () => {\n if (disposed) throw new Error('打印会话已关闭,请重新生成预览');\n checkCancelled(lifetime.signal);\n if (busy) throw new Error('正在处理上一项任务,请稍候');\n };\n const preparedMs = performance.now() - started;\n return {\n layout,\n preparedMs,\n async thumbnail(index: number, maxWidth = 480): Promise<string> {\n assertLive();\n if (!Number.isInteger(index) || index < 0 || index >= layout.pages.length) throw new Error('预览页码无效');\n busy = true;\n let sheet: HTMLCanvasElement | undefined;\n let thumb: HTMLCanvasElement | undefined;\n try {\n const page = layout.pages[index];\n const body = await renderer.capture(layout.root, page.start, page.end - page.start);\n try {\n const headerCanvas = layout.header ? await renderer.capture(layout.header, 0, layout.headerHeight / layout.ratio) : undefined;\n const footerCanvas = layout.footer ? await renderer.capture(layout.footer, 0, layout.footerHeight / layout.ratio) : undefined;\n try {\n sheet = composePageCanvas(body, (page.end - page.start) * layout.ratio, index, { geometry: layout, settings, headerCanvas, footerCanvas, totalPages: layout.pages.length });\n } finally { if (headerCanvas) renderer.release(headerCanvas); if (footerCanvas) renderer.release(footerCanvas); }\n } finally { renderer.release(body); }\n thumb = document.createElement('canvas');\n thumb.width = Math.max(1, Math.min(640, maxWidth, sheet.width));\n thumb.height = Math.ceil(sheet.height * thumb.width / sheet.width);\n const ctx = thumb.getContext('2d');\n if (!ctx) throw new Error('浏览器无法生成预览');\n ctx.drawImage(sheet, 0, 0, thumb.width, thumb.height);\n checkCancelled(lifetime.signal);\n return thumb.toDataURL('image/jpeg', 0.85);\n } finally {\n if (sheet) { sheet.width = 0; sheet.height = 0; }\n if (thumb) { thumb.width = 0; thumb.height = 0; }\n busy = false;\n }\n },\n async exportDocument(params: Omit<DocumentExportOptions, 'element' | 'settings'>) {\n assertLive(); busy = true;\n const controller = new AbortController();\n const cancel = () => controller.abort();\n lifetime.signal.addEventListener('abort', cancel, { once: true });\n params.signal?.addEventListener('abort', cancel, { once: true });\n if (params.signal?.aborted || lifetime.signal.aborted) controller.abort();\n try { return await exportPreparedLayout(layout, { ...params, settings, signal: controller.signal }, preparedMs); }\n finally {\n lifetime.signal.removeEventListener('abort', cancel);\n params.signal?.removeEventListener('abort', cancel);\n busy = false;\n }\n },\n dispose() {\n if (disposed) return;\n disposed = true; lifetime.abort(); renderer.dispose(); layout.cleanup();\n options.signal?.removeEventListener('abort', forwardAbort);\n },\n };\n}\nexport type PrintSession = Awaited<ReturnType<typeof createPrintSession>>;\n"],"names":["createPrintSession","options","lifetime","forwardAbort","_a","_b","started","layout","prepareLayout","error","_c","renderer","createPageCapture","settings","disposed","busy","assertLive","checkCancelled","preparedMs","index","maxWidth","sheet","thumb","page","body","headerCanvas","footerCanvas","composePageCanvas","ctx","params","controller","cancel","exportPreparedLayout"],"mappings":"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"}