{"allowContribute":false,"item":{"artifactHtml":"\u003cstyle\u003e*{box-sizing:border-box}\n:root { --paper:#FDFBF9; --ink:#1A1412; --ink-2:#6B5E5B; --accent:#D93A2B; --accent-2:#1A7A6E; --soft:#FCECE9; --soft2:#E8F4F1; --hair:#E8DDDB; --warn:#FFF3E0; }\n:root[data-theme=\"dark\"] { --paper:#161211; --ink:#F0E8E6; --ink-2:#B8A9A6; --accent:#FF6B5A; --accent-2:#4ECDC4; --soft:#2A1E1C; --soft2:#14302E; --hair:#2E2422; --warn:#2A2210; }\n.doc { background:var(--paper); color:var(--ink); padding:30px 32px; font:16px/1.78 -apple-system,\"PingFang TC\",\"Noto Sans TC\",sans-serif; max-width:820px; margin:0 auto; }\n.eyebrow { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.16em; color:var(--accent); text-transform:uppercase; }\nh1 { font-size:24px; line-height:1.35; letter-spacing:-.02em; margin:10px 0 0; }\n.lede { color:var(--ink-2); font-size:15px; line-height:1.75; margin:12px 0 0; max-width:66ch; }\n.lede code { font-family:ui-monospace,Menlo,monospace; font-size:13px; background:var(--soft); padding:2px 6px; border-radius:4px; color:var(--accent); word-break:break-all; }\n.stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:10px; margin:20px 0; }\n.stat { background:var(--soft); border:1px solid var(--hair); border-radius:10px; padding:13px 14px; }\n.stat.dark { background:var(--soft2); }\n.stat .k { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; color:var(--ink-2); }\n.stat .v { font-size:16px; font-weight:800; margin-top:6px; line-height:1.25; }\n.stat .n { font-size:12px; color:var(--ink-2); margin-top:4px; line-height:1.45; }\n.callout { display:flex; gap:12px; padding:14px 16px; background:var(--warn); border:1px solid #F5D7A0; border-radius:10px; margin:18px 0; }\n:root[data-theme=\"dark\"] .callout { border-color:#5A4A1A; }\n.callout .tag { flex:none; font:800 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; color:#B45309; padding-top:2px; }\n:root[data-theme=\"dark\"] .callout .tag { color:#FBBF24; }\nh2 { font-size:16px; letter-spacing:-.01em; margin:26px 0 10px; padding-bottom:8px; border-bottom:1px solid var(--hair); }\nh3 { font-size:14px; margin:18px 0 8px; color:var(--ink); }\np { color:var(--ink-2); margin:10px 0; max-width:68ch; font-size:14.5px; line-height:1.8; }\nul,ol { margin:8px 0 12px 20px; color:var(--ink-2); font-size:14.5px; line-height:1.8; }\nli { margin:4px 0; }\nli strong { color:var(--ink); }\n.mono { font-family:ui-monospace,Menlo,monospace; font-size:13px; }\ntable { border-collapse:collapse; width:100%; font-size:13.5px; margin:12px 0; }\nth,td { text-align:left; padding:9px 12px; border-bottom:1px solid var(--hair); }\nth { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.06em; color:var(--ink-2); background:var(--soft); }\ntd { color:var(--ink-2); }\ntd strong { color:var(--ink); }\n.pill { display:inline-block; font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.06em; padding:3px 8px; border-radius:999px; }\n.pill-red { background:var(--soft); color:var(--accent); border:1px solid var(--hair); }\n.pill-green { background:var(--soft2); color:var(--accent-2); border:1px solid #C7E8E0; }\n:root[data-theme=\"dark\"] .pill-green { border-color:#1F4A45; }\n.codeblock { background:#1A1A1E; color:#E8E8EA; border-radius:10px; padding:14px 16px; font:13px/1.65 ui-monospace,Menlo,monospace; overflow-x:auto; margin:12px 0; white-space:pre-wrap; word-break:break-all; }\n:root[data-theme=\"dark\"] .codeblock { background:#0F0F12; }\n.compare { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:12px 0; }\n.compare .box { border:1px solid var(--hair); border-radius:10px; padding:14px; }\n.compare .box.bad { background:var(--soft); }\n.compare .box.good { background:var(--soft2); }\n.box .label { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; margin-bottom:6px; }\n.box.bad .label { color:var(--accent); }\n.box.good .label { color:var(--accent-2); }\n.box code { font-size:12.5px; word-break:break-all; }\n@media (max-width:640px) { .doc{padding:22px 18px;} h1{font-size:20px;} .compare{grid-template-columns:1fr;} }\n.wrap{display:block;width:100%;max-width:100%;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;overscroll-behavior-inline:contain;scrollbar-width:thin;scrollbar-color:var(--hair) transparent;touch-action:pan-x;margin:10px 0;border-radius:6px;isolation:isolate}\n.wrap::-webkit-scrollbar{height:6px}\n.wrap::-webkit-scrollbar-thumb{background:var(--hair);border-radius:3px}\n.wrap::-webkit-scrollbar-track{background:transparent}\n.wrap table{margin:0}\n.scroll-hint{font:11px ui-monospace;color:var(--ink-2);opacity:.7;margin:10px 0 -4px;display:none}\n@media(max-width:640px){.doc{padding:20px 14px;overflow-x:hidden}h1{font-size:20px}.wrap{margin-left:-14px;margin-right:-14px;padding:0 14px;width:auto;max-width:none;border-radius:0}.scroll-hint{display:block}table{min-width:600px}}\n\u003c/style\u003e\u003cdiv class=\"doc\"\u003e\n\u003cheader\u003e\n\u003cdiv class=\"eyebrow\"\u003eBUG REPORT · 2026-08-28 · 均線回測 MA_BACKTEST / pdf.fromHTML 誤用\u003c/div\u003e\n\u003ch1\u003eCubeLV 平台 Bug 回報：均線回測 PDF 用截圖直出，版面爆版且字糊 — 6669 緯穎案例\u003c/h1\u003e\n\u003cp class=\"lede\"\u003e均線回測 詳情頁的「匯出 PDF」目前把整塊互動儀表板以 \u003ccode\u003epdf.fromHTML\u003c/code\u003e 截圖灌進 A4，DPI 被算成 \u003ccode\u003e15×\u003c/code\u003e（\u003ccode\u003e695×15 = 10425pt\u003c/code\u003e 遠超 A4 寬 \u003ccode\u003e595pt\u003c/code\u003e），95% 內容落在頁外；\u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e K 線直接丟失空白、\u003ccode\u003eMA15-50\u003c/code\u003e 表格被柵格化成圖片、字無法選取不可分頁。依 \u003ccode\u003egenerate-pdf\u003c/code\u003e 規範此類報告應改用 \u003ccode\u003epdf.fromBlocks\u003c/code\u003e 結構化排版。使用者體感：\u003cstrong\u003e「不如不要設計這功能」\u003c/strong\u003e。\u003c/p\u003e\n\u003c/header\u003e\n\u003csection data-cube=\"stats\" class=\"stats\"\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e影響插件\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:14px\"\u003e均線勝率回測\u003c/div\u003e\u003cdiv class=\"n\"\u003e1094ede45c853958cce864e5 / MaBacktestDetailView\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e嚴重程度\u003c/div\u003e\u003cdiv class=\"v\" style=\"color:var(--accent)\"\u003e🟡 中\u003c/div\u003e\u003cdiv class=\"n\"\u003e功能可用但交付物醜，建議先下架入口\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e案例檔案\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:13px\"\u003e均線回測 - 6669 緯穎.pdf\u003c/div\u003e\u003cdiv class=\"n\"\u003e52,311 bytes · 1 頁 · A4 595×842\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat dark\"\u003e\u003cdiv class=\"k\"\u003e生成方式\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:13px\"\u003epdf.fromHTML + 截圖\u003c/div\u003e\u003cdiv class=\"n\"\u003escale 15× · SMask 透明\u003c/div\u003e\u003c/div\u003e\n\u003c/section\u003e\n\u003cdiv class=\"callout\"\u003e\u003cspan class=\"tag\"\u003e核心判斷\u003c/span\u003e\u003cdiv style=\"font-size:14px; line-height:1.7; color:var(--ink)\"\u003e這不是缺字或樣式跑版，是\u003cstrong\u003e「互動儀表板被當成文件版所見即所得」\u003c/strong\u003e的選型錯誤：\u003ccode\u003efromHTML\u003c/code\u003e 在 web/mobile 是「抽文字重排」，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e 天生會丟；把熱力圖+表格整塊柵格化成 695×695 圖片再硬縮放，等於同時放棄了文字可選取、自動分頁與中文斷行三個 host 已做好的能力。\u003c/div\u003e\u003c/div\u003e\n\u003ch2\u003e一、現象重述\u003c/h2\u003e\n\u003cdiv class=\"compare\"\u003e\n\u003cdiv class=\"box bad\"\u003e\u003cdiv class=\"label\"\u003e✕ 現在這份 PDF 看起來\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003e頁首三行字正常（標題/日期/CubeLV + 一條灰線），下方大面積空白，左上角一小塊糊掉的色塊。K 線區全白，MA 表格字糊無法複製，無分頁。\u003c/p\u003e\u003c/div\u003e\n\u003cdiv class=\"box good\"\u003e\u003cdiv class=\"label\"\u003e✓ 報告該長這樣\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003eA4 多頁文件：推薦 MA22 53.8% 摘要 → 熱力圖文字摘要 → MA15-50 完整對照表（可選取、★ 標 BEST、自動分頁）→ K 線可選附圖 → 參數與免責。\u003c/p\u003e\u003c/div\u003e\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e熱力圖格子原本是 \u003ccode\u003e\u0026lt;div\u0026gt; grid\u003c/code\u003e，應為文字，現被壓進一張帶 \u003ccode\u003eSMask\u003c/code\u003e 的圖片\u003c/li\u003e\n\u003cli\u003eK 線是 \u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e，\u003ccode\u003efromHTML\u003c/code\u003e 抽字時被直接捨棄\u003c/li\u003e\n\u003cli\u003e36 列 MA 表從「文字表格」變「圖片」，DPI 又放大 15 倍，印出來糊且不可搜尋\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e二、解包證據（直接讀 PDF 物件）\u003c/h2\u003e\n\u003cdiv class=\"scroll-hint\"\u003e← 左右滑動查看完整表格 →\u003c/div\u003e\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e物件\u003c/th\u003e\u003cth\u003e實測值\u003c/th\u003e\u003cth\u003e判讀\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 7 Page\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eMediaBox 595.28×841.89\u003c/code\u003e（A4）\u003c/td\u003e\u003ctd\u003e容器正確\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 8 Contents\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e僅 3 段 \u003ccode\u003eTj\u003c/code\u003e（標題/日期/CubeLV）+ \u003ccode\u003eImage Do\u003c/code\u003e + 一條線\u003c/td\u003e\u003ctd\u003e除了標頭，其他全塞在一張圖裡\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 6 Image\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 RGB / FlateDecode / 14,491,075 bytes\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eDetailView 整塊截圖\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 17 SMask\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 Gray / Decode [0 1] / mean α 52/255\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e圓角裁切用遮罩，平均半透，邊緣鋸齒\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eTransform\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1 0 0 1 481.8 743.4 cm\u003c/code\u003e → \u003ccode\u003e15 0 0 15\u003c/code\u003e → \u003ccode\u003eDo\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003cspan class=\"pill pill-red\"\u003e爆版主因\u003c/span\u003e 695×15=10425pt，A4 僅 595pt，95% 在頁外被裁\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003ebbox（α\u0026gt;10）\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e467×568\u003c/code\u003e（x120-587, y64-631）\u003c/td\u003e\u003ctd\u003e有效內容僅約 2/3 張圖，周圍全透明留白\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e字型\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eNotoSansTC Regular/SemiBold CIDFontType2\u003c/code\u003e 正常內嵌\u003c/td\u003e\u003ctd\u003e缺字不是原因，是圖片化\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e\n\u003cdiv class=\"codeblock\"\u003eq\n1 0 0 1 481.855 743.439 cm\n1 0 0 1 0 0 cm\n15 0 0 15 0 0 cm   ← 這一行把 695px 圖放大 15 倍\n/Image-9750469207 Do\nQ\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e結論：\u003c/strong\u003eDPI 換算錯誤。可能是把 CSS px 當 pt 直乘，或把「為了 Retina 截 2×」的邏輯疊加到 PDF pt 上，宿主已處理 CJK 字型，插件不該自己再算縮放。\u003c/p\u003e\n\u003ch2\u003e三、重現步驟\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e打開 \u003ccode\u003e均線勝率回測\u003c/code\u003e 插件 → 選 \u003ccode\u003e6669 緯穎 MA22 53.8%\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e）\u003c/li\u003e\n\u003cli\u003e點「匯出 PDF / 下載報告」\u003c/li\u003e\n\u003cli\u003e檔案庫 \u003ccode\u003e聊天室檔案\u003c/code\u003e 收到 \u003ccode\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e，s3Key \u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e）\u003c/li\u003e\n\u003cli\u003e打開即見標頭正常、下方空白+糊塊；文字不可選取\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e四、根因：為何 \u003ccode\u003efromHTML\u003c/code\u003e 不適合這頁\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003epdf.fromHTML\u003c/code\u003e 定位是「已有富文本/預覽 HTML 的文件」所見即所得；在 web/mobile 會\u003cstrong\u003e抽文字結構重排\u003c/strong\u003e，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e、\u003ccode\u003eShadow DOM\u003c/code\u003e 內容不在抽取範圍內 → K 線直接消失\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epdf.fromBlocks\u003c/code\u003e 定位是「結構化資料排版成公文/報告」：標題 + 多區段 + 表格，host 負責 A4 分頁、中文逐字斷行、CJK 內嵌字型，插件只給資料\u003c/li\u003e\n\u003cli\u003e此頁本質是\u003cstrong\u003e報告\u003c/strong\u003e（推薦 MA、勝率表、參數說明），不是文章。正確選型是後者；前者硬套才會走到「整頁截圖 → SMask → 15×」這條歪路\u003c/li\u003e\n\u003cli\u003e技能 \u003ccode\u003egenerate-pdf\u003c/code\u003e 明確提醒：\u003cem\u003e不要用 python / 不要自夾字型 / 不要自引 pdf-lib，一律用 \u003ccode\u003e@cubelv/sdk\u003c/code\u003e 的 \u003ccode\u003epdf\u003c/code\u003e\u003c/em\u003e，但也要選對 API\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e五、建議修復\u003c/h2\u003e\n\u003ch3\u003eP0 — 先止血（今天可做）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e隱藏或灰階 DetailView 的「匯出 PDF」按鈕，改顯示「報告版型重做中」；檔案庫此份醜檔不主動推播\u003c/li\u003e\n\u003cli\u003e若要保留入口，先彈提示：「目前版型為測試版，建議先用 App 內分享」\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eP1 — 改用 \u003ccode\u003efromBlocks\u003c/code\u003e 重做（建議版型）\u003c/h3\u003e\n\u003cdiv class=\"codeblock\"\u003eimport { pdf } from '@cubelv/sdk';\nimport { saveBlobToDisk } from '@cubelv/sdk';\nconst blob = await pdf.fromBlocks({\n  title: `均線回測 - ${stockCode} ${stockName}`,\n  sections: [\n    { title: '壹、標的與推薦', content: `${stockCode} ${stockName}｜日線 ${dailyCount} 筆｜回測日 ${backtestDate.slice(0,10)}\\n推薦：MA${bestMA} 勝率 ${winRate}%（${tradeCount}次）｜均報 ${avgReturn}%\\n策略：E 策略 收盤突破進 / 1%+肉眼(High\u0026lt;MA×0.99)+二日才出` },\n    { title: '貳、熱力圖摘要', content: `MA15→MA50 勝率分佈文字摘要（最佳 MA${bestMA} 標 ★，其餘列勝率/次數）` },\n    { title: '參、完整對照表 MA15-50', content: rows.map(r =\u003e `MA${r.ma}  勝率 ${r.winRate}%  次數 ${r.trades}  均報 ${r.avgReturn}%  最大虧 ${r.maxLoss}%  盤中最大虧 ${r.maxIntra}%  持有 ${r.avgHold}/${r.worstHold}天 ${r.ma===bestMA?'★BEST':''}`).join('\\n') },\n    { title: '肆、參數與免責', content: `資料源：TWSE STOCK_DAY / Yahoo v8（adjclose 已還原）\\n門檻：勝率 ≥51% 且 \u0026gt;5 次才算 BEST；放棄門檻 \u0026gt;50日無符合\\n免責：歷史回測僅供參考，不構成投資建議` },\n  ],\n});\nawait saveBlobToDisk(blob, `均線回測 - ${stockCode} ${stockName}.pdf`, 'application/pdf');\n// K 線如需附圖：canvas.toDataURL() 轉 \u0026lt;img\u0026gt; 插在最後一段，勿整頁截圖\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e好處：文字可選取、可搜尋、自動分頁、中文不會被切字、中文字型由 host 統一內嵌\u003c/li\u003e\n\u003cli\u003e表格 36 列用等寬文字排版，host 會自動跨頁，不會糊\u003c/li\u003e\n\u003cli\u003eK 線如要保留，用 \u003ccode\u003ecanvas.toDataURL('image/png')\u003c/code\u003e 單獨轉一張適當 DPI 的圖插在最後一頁即可\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eP2 — 品質門檻\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e新增前後對比截圖驗收：文字可選取、A4 邊距 56pt 內不溢出、無 15× 放大\u003c/li\u003e\n\u003cli\u003e補一個 36 列長表的分頁測試（確保第二頁表頭重複或至少可讀）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e六、當前規避（給使用者）\u003c/h2\u003e\n\u003cp\u003e在改版前，請直接在 App 內看 \u003ccode\u003e勝率熱力圖\u003c/code\u003e 與 \u003ccode\u003e完整對照表\u003c/code\u003e，不要依賴此 PDF 做列印或分享。此 PDF 的 \u003ccode\u003eFILE\u003c/code\u003e 刪除為\u003cstrong\u003e永久刪除、不可還原\u003c/strong\u003e，若覺礙眼可請 CEO 協助刪除（刪前會二次確認）。\u003c/p\u003e\n\u003ch2\u003e七、QA 複測資訊\u003c/h2\u003e\n\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e欄位\u003c/th\u003e\u003cth\u003e內容\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\n\u003ctr\u003e\u003ctd\u003e回報時間\u003c/td\u003e\u003ctd\u003e2026-08-28 07:38 UTC（pdf CreationDate \u003ccode class=\"mono\"\u003eD:20260828073848Z\u003c/code\u003e）\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e檔案\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e / \u003ccode class=\"mono\"\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e / \u003ccode class=\"mono\"\u003eFILE_FOLDER 聊天室檔案 6a4b63eb8e9022a22716f09c\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003es3Key\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eMA item\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e — 6669 緯穎 MA22 53.8% · 日線筆數待補（由 \u003ccode\u003edailyCount\u003c/code\u003e 帶入）\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e插件\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e1094ede45c853958cce864e5\u003c/code\u003e 均線勝率回測 / 視圖 \u003ccode\u003eMaBacktestDetailView\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e期望\u003c/td\u003e\u003ctd\u003e匯出為可列印、可選取的 A4 報告，而非糊掉的截圖\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e\n\u003cp style=\"margin-top:18px; font-size:12px; color:var(--ink-2); border-top:1px solid var(--hair); padding-top:12px;\"\u003e備註：本頁由 PDF 二進位解包驗證（FlateDecode 解壓 + ToUnicode CMap 對照 + SMask/Transform 量測），非目測臆測。若之後要追此 bug 的修復分支，請以此 FILE id 回放即可重現。\u003c/p\u003e\n\u003c/div\u003e","content":"\u003cdiv class=\"doc\"\u003e  \u003ctable\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e影響插件\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e均線勝率回測\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e1094ede45c853958cce864e5 / MaBacktestDetailView\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e嚴重程度\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e🟡 中\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e功能可用但交付物醜，建議先下架入口\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e案例檔案\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e均線回測 - 6669 緯穎.pdf\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e52,311 bytes · 1 頁 · A4 595×842\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e生成方式\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003epdf.fromHTML + 截圖\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003escale 15× · SMask 透明\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e \u003cdiv class=\"callout\"\u003e\u003cspan class=\"tag\"\u003e核心判斷\u003c/span\u003e\u003cdiv style=\"font-size:14px; line-height:1.7; color:var(--ink)\"\u003e這不是缺字或樣式跑版，是\u003cstrong\u003e「互動儀表板被當成文件版所見即所得」\u003c/strong\u003e的選型錯誤：\u003ccode\u003efromHTML\u003c/code\u003e 在 web/mobile 是「抽文字重排」，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e 天生會丟；把熱力圖+表格整塊柵格化成 695×695 圖片再硬縮放，等於同時放棄了文字可選取、自動分頁與中文斷行三個 host 已做好的能力。\u003c/div\u003e\u003c/div\u003e \u003ch2\u003e一、現象重述\u003c/h2\u003e \u003cdiv class=\"compare\"\u003e \u003cdiv class=\"box bad\"\u003e\u003cdiv class=\"label\"\u003e✕ 現在這份 PDF 看起來\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003e頁首三行字正常（標題/日期/CubeLV + 一條灰線），下方大面積空白，左上角一小塊糊掉的色塊。K 線區全白，MA 表格字糊無法複製，無分頁。\u003c/p\u003e\u003c/div\u003e \u003cdiv class=\"box good\"\u003e\u003cdiv class=\"label\"\u003e✓ 報告該長這樣\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003eA4 多頁文件：推薦 MA22 53.8% 摘要 → 熱力圖文字摘要 → MA15-50 完整對照表（可選取、★ 標 BEST、自動分頁）→ K 線可選附圖 → 參數與免責。\u003c/p\u003e\u003c/div\u003e \u003c/div\u003e \u003cul\u003e \u003cli\u003e熱力圖格子原本是 \u003ccode\u003e\u0026lt;div\u0026gt; grid\u003c/code\u003e，應為文字，現被壓進一張帶 \u003ccode\u003eSMask\u003c/code\u003e 的圖片\u003c/li\u003e \u003cli\u003eK 線是 \u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e，\u003ccode\u003efromHTML\u003c/code\u003e 抽字時被直接捨棄\u003c/li\u003e \u003cli\u003e36 列 MA 表從「文字表格」變「圖片」，DPI 又放大 15 倍，印出來糊且不可搜尋\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e二、解包證據（直接讀 PDF 物件）\u003c/h2\u003e \u003cdiv class=\"scroll-hint\"\u003e← 左右滑動查看完整表格 →\u003c/div\u003e\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e物件\u003c/th\u003e\u003cth\u003e實測值\u003c/th\u003e\u003cth\u003e判讀\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 7 Page\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eMediaBox 595.28×841.89\u003c/code\u003e（A4）\u003c/td\u003e\u003ctd\u003e容器正確\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 8 Contents\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e僅 3 段 \u003ccode\u003eTj\u003c/code\u003e（標題/日期/CubeLV）+ \u003ccode\u003eImage Do\u003c/code\u003e + 一條線\u003c/td\u003e\u003ctd\u003e除了標頭，其他全塞在一張圖裡\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 6 Image\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 RGB / FlateDecode / 14,491,075 bytes\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eDetailView 整塊截圖\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 17 SMask\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 Gray / Decode [0 1] / mean α 52/255\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e圓角裁切用遮罩，平均半透，邊緣鋸齒\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eTransform\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1 0 0 1 481.8 743.4 cm\u003c/code\u003e → \u003ccode\u003e15 0 0 15\u003c/code\u003e → \u003ccode\u003eDo\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003cspan class=\"pill pill-red\"\u003e爆版主因\u003c/span\u003e 695×15=10425pt，A4 僅 595pt，95% 在頁外被裁\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003ebbox（α\u0026gt;10）\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e467×568\u003c/code\u003e（x120-587, y64-631）\u003c/td\u003e\u003ctd\u003e有效內容僅約 2/3 張圖，周圍全透明留白\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e字型\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eNotoSansTC Regular/SemiBold CIDFontType2\u003c/code\u003e 正常內嵌\u003c/td\u003e\u003ctd\u003e缺字不是原因，是圖片化\u003c/td\u003e\u003c/tr\u003e \u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e \u003cdiv class=\"codeblock\"\u003eq 1 0 0 1 481.855 743.439 cm 1 0 0 1 0 0 cm 15 0 0 15 0 0 cm   ← 這一行把 695px 圖放大 15 倍 /Image-9750469207 Do Q\u003c/div\u003e \u003cp\u003e\u003cstrong\u003e結論：\u003c/strong\u003eDPI 換算錯誤。可能是把 CSS px 當 pt 直乘，或把「為了 Retina 截 2×」的邏輯疊加到 PDF pt 上，宿主已處理 CJK 字型，插件不該自己再算縮放。\u003c/p\u003e \u003ch2\u003e三、重現步驟\u003c/h2\u003e \u003col\u003e \u003cli\u003e打開 \u003ccode\u003e均線勝率回測\u003c/code\u003e 插件 → 選 \u003ccode\u003e6669 緯穎 MA22 53.8%\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e）\u003c/li\u003e \u003cli\u003e點「匯出 PDF / 下載報告」\u003c/li\u003e \u003cli\u003e檔案庫 \u003ccode\u003e聊天室檔案\u003c/code\u003e 收到 \u003ccode\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e，s3Key \u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e）\u003c/li\u003e \u003cli\u003e打開即見標頭正常、下方空白+糊塊；文字不可選取\u003c/li\u003e \u003c/ol\u003e \u003ch2\u003e四、根因：為何 \u003ccode\u003efromHTML\u003c/code\u003e 不適合這頁\u003c/h2\u003e \u003cul\u003e \u003cli\u003e\u003ccode\u003epdf.fromHTML\u003c/code\u003e 定位是「已有富文本/預覽 HTML 的文件」所見即所得；在 web/mobile 會\u003cstrong\u003e抽文字結構重排\u003c/strong\u003e，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e、\u003ccode\u003eShadow DOM\u003c/code\u003e 內容不在抽取範圍內 → K 線直接消失\u003c/li\u003e \u003cli\u003e\u003ccode\u003epdf.fromBlocks\u003c/code\u003e 定位是「結構化資料排版成公文/報告」：標題 + 多區段 + 表格，host 負責 A4 分頁、中文逐字斷行、CJK 內嵌字型，插件只給資料\u003c/li\u003e \u003cli\u003e此頁本質是\u003cstrong\u003e報告\u003c/strong\u003e（推薦 MA、勝率表、參數說明），不是文章。正確選型是後者；前者硬套才會走到「整頁截圖 → SMask → 15×」這條歪路\u003c/li\u003e \u003cli\u003e技能 \u003ccode\u003egenerate-pdf\u003c/code\u003e 明確提醒：\u003cem\u003e不要用 python / 不要自夾字型 / 不要自引 pdf-lib，一律用 \u003ccode\u003e@cubelv/sdk\u003c/code\u003e 的 \u003ccode\u003epdf\u003c/code\u003e\u003c/em\u003e，但也要選對 API\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e五、建議修復\u003c/h2\u003e \u003ch3\u003eP0 — 先止血（今天可做）\u003c/h3\u003e \u003cul\u003e \u003cli\u003e隱藏或灰階 DetailView 的「匯出 PDF」按鈕，改顯示「報告版型重做中」；檔案庫此份醜檔不主動推播\u003c/li\u003e \u003cli\u003e若要保留入口，先彈提示：「目前版型為測試版，建議先用 App 內分享」\u003c/li\u003e \u003c/ul\u003e \u003ch3\u003eP1 — 改用 \u003ccode\u003efromBlocks\u003c/code\u003e 重做（建議版型）\u003c/h3\u003e \u003cdiv class=\"codeblock\"\u003eimport { pdf } from '@cubelv/sdk'; import { saveBlobToDisk } from '@cubelv/sdk'; const blob = await pdf.fromBlocks({ title: `均線回測 - ${stockCode} ${stockName}`, sections: [ { title: '壹、標的與推薦', content: `${stockCode} ${stockName}｜日線 ${dailyCount} 筆｜回測日 ${backtestDate.slice(0,10)}\\n推薦：MA${bestMA} 勝率 ${winRate}%（${tradeCount}次）｜均報 ${avgReturn}%\\n策略：E 策略 收盤突破進 / 1%+肉眼(High\u0026lt;MA×0.99)+二日才出` }, { title: '貳、熱力圖摘要', content: `MA15→MA50 勝率分佈文字摘要（最佳 MA${bestMA} 標 ★，其餘列勝率/次數）` }, { title: '參、完整對照表 MA15-50', content: rows.map(r =\u0026gt; `MA${r.ma}  勝率 ${r.winRate}%  次數 ${r.trades}  均報 ${r.avgReturn}%  最大虧 ${r.maxLoss}%  盤中最大虧 ${r.maxIntra}%  持有 ${r.avgHold}/${r.worstHold}天 ${r.ma===bestMA?'★BEST':''}`).join('\\n') }, { title: '肆、參數與免責', content: `資料源：TWSE STOCK_DAY / Yahoo v8（adjclose 已還原）\\n門檻：勝率 ≥51% 且 \u0026gt;5 次才算 BEST；放棄門檻 \u0026gt;50日無符合\\n免責：歷史回測僅供參考，不構成投資建議` }, ], }); await saveBlobToDisk(blob, `均線回測 - ${stockCode} ${stockName}.pdf`, 'application/pdf'); // K 線如需附圖：canvas.toDataURL() 轉 \u0026lt;img\u0026gt; 插在最後一段，勿整頁截圖\u003c/div\u003e \u003cul\u003e \u003cli\u003e好處：文字可選取、可搜尋、自動分頁、中文不會被切字、中文字型由 host 統一內嵌\u003c/li\u003e \u003cli\u003e表格 36 列用等寬文字排版，host 會自動跨頁，不會糊\u003c/li\u003e \u003cli\u003eK 線如要保留，用 \u003ccode\u003ecanvas.toDataURL('image/png')\u003c/code\u003e 單獨轉一張適當 DPI 的圖插在最後一頁即可\u003c/li\u003e \u003c/ul\u003e \u003ch3\u003eP2 — 品質門檻\u003c/h3\u003e \u003cul\u003e \u003cli\u003e新增前後對比截圖驗收：文字可選取、A4 邊距 56pt 內不溢出、無 15× 放大\u003c/li\u003e \u003cli\u003e補一個 36 列長表的分頁測試（確保第二頁表頭重複或至少可讀）\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e六、當前規避（給使用者）\u003c/h2\u003e \u003cp\u003e在改版前，請直接在 App 內看 \u003ccode\u003e勝率熱力圖\u003c/code\u003e 與 \u003ccode\u003e完整對照表\u003c/code\u003e，不要依賴此 PDF 做列印或分享。此 PDF 的 \u003ccode\u003eFILE\u003c/code\u003e 刪除為\u003cstrong\u003e永久刪除、不可還原\u003c/strong\u003e，若覺礙眼可請 CEO 協助刪除（刪前會二次確認）。\u003c/p\u003e \u003ch2\u003e七、QA 複測資訊\u003c/h2\u003e \u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e欄位\u003c/th\u003e\u003cth\u003e內容\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e \u003ctr\u003e\u003ctd\u003e回報時間\u003c/td\u003e\u003ctd\u003e2026-08-28 07:38 UTC（pdf CreationDate \u003ccode class=\"mono\"\u003eD:20260828073848Z\u003c/code\u003e）\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e檔案\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e / \u003ccode class=\"mono\"\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e / \u003ccode class=\"mono\"\u003eFILE_FOLDER 聊天室檔案 6a4b63eb8e9022a22716f09c\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003es3Key\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003eMA item\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e — 6669 緯穎 MA22 53.8% · 日線筆數待補（由 \u003ccode\u003edailyCount\u003c/code\u003e 帶入）\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e插件\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e1094ede45c853958cce864e5\u003c/code\u003e 均線勝率回測 / 視圖 \u003ccode\u003eMaBacktestDetailView\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e期望\u003c/td\u003e\u003ctd\u003e匯出為可列印、可選取的 A4 報告，而非糊掉的截圖\u003c/td\u003e\u003c/tr\u003e \u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e \u003cp style=\"margin-top:18px; font-size:12px; color:var(--ink-2); border-top:1px solid var(--hair); padding-top:12px;\"\u003e備註：本頁由 PDF 二進位解包驗證（FlateDecode 解壓 + ToUnicode CMap 對照 + SMask/Transform 量測），非目測臆測。若之後要追此 bug 的修復分支，請以此 FILE id 回放即可重現。\u003c/p\u003e \u003c/div\u003e","createdAt":1787903716010,"deletedAt":null,"displayMode":"artifact","embedRenders":{},"id":"c05656c14441f7ff0679f2e7","isNew":false,"isPublic":true,"itemType":"NOTE","name":"CubeLV 平台 Bug 回報：均線回測 PDF 用截圖直出，版面爆版且字糊 — 6669 緯穎案例","parents":{"4465d0a863da5d1b345d888c":1787903716010},"preParentID":null,"updatedAt":1788205268080,"updatedBy":{"userId":"6a3dcfc700e9b9fd06d5ef","userName":"蔡其樺"},"version":12},"ownerName":"蔡其樺","subtree":[{"artifactHtml":"\u003cstyle\u003e*{box-sizing:border-box}\n:root { --paper:#FDFBF9; --ink:#1A1412; --ink-2:#6B5E5B; --accent:#D93A2B; --accent-2:#1A7A6E; --soft:#FCECE9; --soft2:#E8F4F1; --hair:#E8DDDB; --warn:#FFF3E0; }\n:root[data-theme=\"dark\"] { --paper:#161211; --ink:#F0E8E6; --ink-2:#B8A9A6; --accent:#FF6B5A; --accent-2:#4ECDC4; --soft:#2A1E1C; --soft2:#14302E; --hair:#2E2422; --warn:#2A2210; }\n.doc { background:var(--paper); color:var(--ink); padding:30px 32px; font:16px/1.78 -apple-system,\"PingFang TC\",\"Noto Sans TC\",sans-serif; max-width:820px; margin:0 auto; }\n.eyebrow { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.16em; color:var(--accent); text-transform:uppercase; }\nh1 { font-size:24px; line-height:1.35; letter-spacing:-.02em; margin:10px 0 0; }\n.lede { color:var(--ink-2); font-size:15px; line-height:1.75; margin:12px 0 0; max-width:66ch; }\n.lede code { font-family:ui-monospace,Menlo,monospace; font-size:13px; background:var(--soft); padding:2px 6px; border-radius:4px; color:var(--accent); word-break:break-all; }\n.stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:10px; margin:20px 0; }\n.stat { background:var(--soft); border:1px solid var(--hair); border-radius:10px; padding:13px 14px; }\n.stat.dark { background:var(--soft2); }\n.stat .k { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; color:var(--ink-2); }\n.stat .v { font-size:16px; font-weight:800; margin-top:6px; line-height:1.25; }\n.stat .n { font-size:12px; color:var(--ink-2); margin-top:4px; line-height:1.45; }\n.callout { display:flex; gap:12px; padding:14px 16px; background:var(--warn); border:1px solid #F5D7A0; border-radius:10px; margin:18px 0; }\n:root[data-theme=\"dark\"] .callout { border-color:#5A4A1A; }\n.callout .tag { flex:none; font:800 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; color:#B45309; padding-top:2px; }\n:root[data-theme=\"dark\"] .callout .tag { color:#FBBF24; }\nh2 { font-size:16px; letter-spacing:-.01em; margin:26px 0 10px; padding-bottom:8px; border-bottom:1px solid var(--hair); }\nh3 { font-size:14px; margin:18px 0 8px; color:var(--ink); }\np { color:var(--ink-2); margin:10px 0; max-width:68ch; font-size:14.5px; line-height:1.8; }\nul,ol { margin:8px 0 12px 20px; color:var(--ink-2); font-size:14.5px; line-height:1.8; }\nli { margin:4px 0; }\nli strong { color:var(--ink); }\n.mono { font-family:ui-monospace,Menlo,monospace; font-size:13px; }\ntable { border-collapse:collapse; width:100%; font-size:13.5px; margin:12px 0; }\nth,td { text-align:left; padding:9px 12px; border-bottom:1px solid var(--hair); }\nth { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.06em; color:var(--ink-2); background:var(--soft); }\ntd { color:var(--ink-2); }\ntd strong { color:var(--ink); }\n.pill { display:inline-block; font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.06em; padding:3px 8px; border-radius:999px; }\n.pill-red { background:var(--soft); color:var(--accent); border:1px solid var(--hair); }\n.pill-green { background:var(--soft2); color:var(--accent-2); border:1px solid #C7E8E0; }\n:root[data-theme=\"dark\"] .pill-green { border-color:#1F4A45; }\n.codeblock { background:#1A1A1E; color:#E8E8EA; border-radius:10px; padding:14px 16px; font:13px/1.65 ui-monospace,Menlo,monospace; overflow-x:auto; margin:12px 0; white-space:pre-wrap; word-break:break-all; }\n:root[data-theme=\"dark\"] .codeblock { background:#0F0F12; }\n.compare { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:12px 0; }\n.compare .box { border:1px solid var(--hair); border-radius:10px; padding:14px; }\n.compare .box.bad { background:var(--soft); }\n.compare .box.good { background:var(--soft2); }\n.box .label { font:700 11px ui-monospace,Menlo,monospace; letter-spacing:.08em; margin-bottom:6px; }\n.box.bad .label { color:var(--accent); }\n.box.good .label { color:var(--accent-2); }\n.box code { font-size:12.5px; word-break:break-all; }\n@media (max-width:640px) { .doc{padding:22px 18px;} h1{font-size:20px;} .compare{grid-template-columns:1fr;} }\n.wrap{display:block;width:100%;max-width:100%;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;overscroll-behavior-inline:contain;scrollbar-width:thin;scrollbar-color:var(--hair) transparent;touch-action:pan-x;margin:10px 0;border-radius:6px;isolation:isolate}\n.wrap::-webkit-scrollbar{height:6px}\n.wrap::-webkit-scrollbar-thumb{background:var(--hair);border-radius:3px}\n.wrap::-webkit-scrollbar-track{background:transparent}\n.wrap table{margin:0}\n.scroll-hint{font:11px ui-monospace;color:var(--ink-2);opacity:.7;margin:10px 0 -4px;display:none}\n@media(max-width:640px){.doc{padding:20px 14px;overflow-x:hidden}h1{font-size:20px}.wrap{margin-left:-14px;margin-right:-14px;padding:0 14px;width:auto;max-width:none;border-radius:0}.scroll-hint{display:block}table{min-width:600px}}\n\u003c/style\u003e\u003cdiv class=\"doc\"\u003e\n\u003cheader\u003e\n\u003cdiv class=\"eyebrow\"\u003eBUG REPORT · 2026-08-28 · 均線回測 MA_BACKTEST / pdf.fromHTML 誤用\u003c/div\u003e\n\u003ch1\u003eCubeLV 平台 Bug 回報：均線回測 PDF 用截圖直出，版面爆版且字糊 — 6669 緯穎案例\u003c/h1\u003e\n\u003cp class=\"lede\"\u003e均線回測 詳情頁的「匯出 PDF」目前把整塊互動儀表板以 \u003ccode\u003epdf.fromHTML\u003c/code\u003e 截圖灌進 A4，DPI 被算成 \u003ccode\u003e15×\u003c/code\u003e（\u003ccode\u003e695×15 = 10425pt\u003c/code\u003e 遠超 A4 寬 \u003ccode\u003e595pt\u003c/code\u003e），95% 內容落在頁外；\u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e K 線直接丟失空白、\u003ccode\u003eMA15-50\u003c/code\u003e 表格被柵格化成圖片、字無法選取不可分頁。依 \u003ccode\u003egenerate-pdf\u003c/code\u003e 規範此類報告應改用 \u003ccode\u003epdf.fromBlocks\u003c/code\u003e 結構化排版。使用者體感：\u003cstrong\u003e「不如不要設計這功能」\u003c/strong\u003e。\u003c/p\u003e\n\u003c/header\u003e\n\u003csection data-cube=\"stats\" class=\"stats\"\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e影響插件\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:14px\"\u003e均線勝率回測\u003c/div\u003e\u003cdiv class=\"n\"\u003e1094ede45c853958cce864e5 / MaBacktestDetailView\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e嚴重程度\u003c/div\u003e\u003cdiv class=\"v\" style=\"color:var(--accent)\"\u003e🟡 中\u003c/div\u003e\u003cdiv class=\"n\"\u003e功能可用但交付物醜，建議先下架入口\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat\"\u003e\u003cdiv class=\"k\"\u003e案例檔案\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:13px\"\u003e均線回測 - 6669 緯穎.pdf\u003c/div\u003e\u003cdiv class=\"n\"\u003e52,311 bytes · 1 頁 · A4 595×842\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"stat dark\"\u003e\u003cdiv class=\"k\"\u003e生成方式\u003c/div\u003e\u003cdiv class=\"v\" style=\"font-size:13px\"\u003epdf.fromHTML + 截圖\u003c/div\u003e\u003cdiv class=\"n\"\u003escale 15× · SMask 透明\u003c/div\u003e\u003c/div\u003e\n\u003c/section\u003e\n\u003cdiv class=\"callout\"\u003e\u003cspan class=\"tag\"\u003e核心判斷\u003c/span\u003e\u003cdiv style=\"font-size:14px; line-height:1.7; color:var(--ink)\"\u003e這不是缺字或樣式跑版，是\u003cstrong\u003e「互動儀表板被當成文件版所見即所得」\u003c/strong\u003e的選型錯誤：\u003ccode\u003efromHTML\u003c/code\u003e 在 web/mobile 是「抽文字重排」，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e 天生會丟；把熱力圖+表格整塊柵格化成 695×695 圖片再硬縮放，等於同時放棄了文字可選取、自動分頁與中文斷行三個 host 已做好的能力。\u003c/div\u003e\u003c/div\u003e\n\u003ch2\u003e一、現象重述\u003c/h2\u003e\n\u003cdiv class=\"compare\"\u003e\n\u003cdiv class=\"box bad\"\u003e\u003cdiv class=\"label\"\u003e✕ 現在這份 PDF 看起來\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003e頁首三行字正常（標題/日期/CubeLV + 一條灰線），下方大面積空白，左上角一小塊糊掉的色塊。K 線區全白，MA 表格字糊無法複製，無分頁。\u003c/p\u003e\u003c/div\u003e\n\u003cdiv class=\"box good\"\u003e\u003cdiv class=\"label\"\u003e✓ 報告該長這樣\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003eA4 多頁文件：推薦 MA22 53.8% 摘要 → 熱力圖文字摘要 → MA15-50 完整對照表（可選取、★ 標 BEST、自動分頁）→ K 線可選附圖 → 參數與免責。\u003c/p\u003e\u003c/div\u003e\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e熱力圖格子原本是 \u003ccode\u003e\u0026lt;div\u0026gt; grid\u003c/code\u003e，應為文字，現被壓進一張帶 \u003ccode\u003eSMask\u003c/code\u003e 的圖片\u003c/li\u003e\n\u003cli\u003eK 線是 \u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e，\u003ccode\u003efromHTML\u003c/code\u003e 抽字時被直接捨棄\u003c/li\u003e\n\u003cli\u003e36 列 MA 表從「文字表格」變「圖片」，DPI 又放大 15 倍，印出來糊且不可搜尋\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e二、解包證據（直接讀 PDF 物件）\u003c/h2\u003e\n\u003cdiv class=\"scroll-hint\"\u003e← 左右滑動查看完整表格 →\u003c/div\u003e\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e物件\u003c/th\u003e\u003cth\u003e實測值\u003c/th\u003e\u003cth\u003e判讀\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 7 Page\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eMediaBox 595.28×841.89\u003c/code\u003e（A4）\u003c/td\u003e\u003ctd\u003e容器正確\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 8 Contents\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e僅 3 段 \u003ccode\u003eTj\u003c/code\u003e（標題/日期/CubeLV）+ \u003ccode\u003eImage Do\u003c/code\u003e + 一條線\u003c/td\u003e\u003ctd\u003e除了標頭，其他全塞在一張圖裡\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 6 Image\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 RGB / FlateDecode / 14,491,075 bytes\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eDetailView 整塊截圖\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 17 SMask\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 Gray / Decode [0 1] / mean α 52/255\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e圓角裁切用遮罩，平均半透，邊緣鋸齒\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eTransform\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1 0 0 1 481.8 743.4 cm\u003c/code\u003e → \u003ccode\u003e15 0 0 15\u003c/code\u003e → \u003ccode\u003eDo\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003cspan class=\"pill pill-red\"\u003e爆版主因\u003c/span\u003e 695×15=10425pt，A4 僅 595pt，95% 在頁外被裁\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003ebbox（α\u0026gt;10）\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e467×568\u003c/code\u003e（x120-587, y64-631）\u003c/td\u003e\u003ctd\u003e有效內容僅約 2/3 張圖，周圍全透明留白\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e字型\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eNotoSansTC Regular/SemiBold CIDFontType2\u003c/code\u003e 正常內嵌\u003c/td\u003e\u003ctd\u003e缺字不是原因，是圖片化\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e\n\u003cdiv class=\"codeblock\"\u003eq\n1 0 0 1 481.855 743.439 cm\n1 0 0 1 0 0 cm\n15 0 0 15 0 0 cm   ← 這一行把 695px 圖放大 15 倍\n/Image-9750469207 Do\nQ\u003c/div\u003e\n\u003cp\u003e\u003cstrong\u003e結論：\u003c/strong\u003eDPI 換算錯誤。可能是把 CSS px 當 pt 直乘，或把「為了 Retina 截 2×」的邏輯疊加到 PDF pt 上，宿主已處理 CJK 字型，插件不該自己再算縮放。\u003c/p\u003e\n\u003ch2\u003e三、重現步驟\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e打開 \u003ccode\u003e均線勝率回測\u003c/code\u003e 插件 → 選 \u003ccode\u003e6669 緯穎 MA22 53.8%\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e）\u003c/li\u003e\n\u003cli\u003e點「匯出 PDF / 下載報告」\u003c/li\u003e\n\u003cli\u003e檔案庫 \u003ccode\u003e聊天室檔案\u003c/code\u003e 收到 \u003ccode\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e，s3Key \u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e）\u003c/li\u003e\n\u003cli\u003e打開即見標頭正常、下方空白+糊塊；文字不可選取\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e四、根因：為何 \u003ccode\u003efromHTML\u003c/code\u003e 不適合這頁\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003epdf.fromHTML\u003c/code\u003e 定位是「已有富文本/預覽 HTML 的文件」所見即所得；在 web/mobile 會\u003cstrong\u003e抽文字結構重排\u003c/strong\u003e，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e、\u003ccode\u003eShadow DOM\u003c/code\u003e 內容不在抽取範圍內 → K 線直接消失\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epdf.fromBlocks\u003c/code\u003e 定位是「結構化資料排版成公文/報告」：標題 + 多區段 + 表格，host 負責 A4 分頁、中文逐字斷行、CJK 內嵌字型，插件只給資料\u003c/li\u003e\n\u003cli\u003e此頁本質是\u003cstrong\u003e報告\u003c/strong\u003e（推薦 MA、勝率表、參數說明），不是文章。正確選型是後者；前者硬套才會走到「整頁截圖 → SMask → 15×」這條歪路\u003c/li\u003e\n\u003cli\u003e技能 \u003ccode\u003egenerate-pdf\u003c/code\u003e 明確提醒：\u003cem\u003e不要用 python / 不要自夾字型 / 不要自引 pdf-lib，一律用 \u003ccode\u003e@cubelv/sdk\u003c/code\u003e 的 \u003ccode\u003epdf\u003c/code\u003e\u003c/em\u003e，但也要選對 API\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e五、建議修復\u003c/h2\u003e\n\u003ch3\u003eP0 — 先止血（今天可做）\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e隱藏或灰階 DetailView 的「匯出 PDF」按鈕，改顯示「報告版型重做中」；檔案庫此份醜檔不主動推播\u003c/li\u003e\n\u003cli\u003e若要保留入口，先彈提示：「目前版型為測試版，建議先用 App 內分享」\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eP1 — 改用 \u003ccode\u003efromBlocks\u003c/code\u003e 重做（建議版型）\u003c/h3\u003e\n\u003cdiv class=\"codeblock\"\u003eimport { pdf } from '@cubelv/sdk';\nimport { saveBlobToDisk } from '@cubelv/sdk';\nconst blob = await pdf.fromBlocks({\n  title: `均線回測 - ${stockCode} ${stockName}`,\n  sections: [\n    { title: '壹、標的與推薦', content: `${stockCode} ${stockName}｜日線 ${dailyCount} 筆｜回測日 ${backtestDate.slice(0,10)}\\n推薦：MA${bestMA} 勝率 ${winRate}%（${tradeCount}次）｜均報 ${avgReturn}%\\n策略：E 策略 收盤突破進 / 1%+肉眼(High\u0026lt;MA×0.99)+二日才出` },\n    { title: '貳、熱力圖摘要', content: `MA15→MA50 勝率分佈文字摘要（最佳 MA${bestMA} 標 ★，其餘列勝率/次數）` },\n    { title: '參、完整對照表 MA15-50', content: rows.map(r =\u003e `MA${r.ma}  勝率 ${r.winRate}%  次數 ${r.trades}  均報 ${r.avgReturn}%  最大虧 ${r.maxLoss}%  盤中最大虧 ${r.maxIntra}%  持有 ${r.avgHold}/${r.worstHold}天 ${r.ma===bestMA?'★BEST':''}`).join('\\n') },\n    { title: '肆、參數與免責', content: `資料源：TWSE STOCK_DAY / Yahoo v8（adjclose 已還原）\\n門檻：勝率 ≥51% 且 \u0026gt;5 次才算 BEST；放棄門檻 \u0026gt;50日無符合\\n免責：歷史回測僅供參考，不構成投資建議` },\n  ],\n});\nawait saveBlobToDisk(blob, `均線回測 - ${stockCode} ${stockName}.pdf`, 'application/pdf');\n// K 線如需附圖：canvas.toDataURL() 轉 \u0026lt;img\u0026gt; 插在最後一段，勿整頁截圖\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e好處：文字可選取、可搜尋、自動分頁、中文不會被切字、中文字型由 host 統一內嵌\u003c/li\u003e\n\u003cli\u003e表格 36 列用等寬文字排版，host 會自動跨頁，不會糊\u003c/li\u003e\n\u003cli\u003eK 線如要保留，用 \u003ccode\u003ecanvas.toDataURL('image/png')\u003c/code\u003e 單獨轉一張適當 DPI 的圖插在最後一頁即可\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eP2 — 品質門檻\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e新增前後對比截圖驗收：文字可選取、A4 邊距 56pt 內不溢出、無 15× 放大\u003c/li\u003e\n\u003cli\u003e補一個 36 列長表的分頁測試（確保第二頁表頭重複或至少可讀）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e六、當前規避（給使用者）\u003c/h2\u003e\n\u003cp\u003e在改版前，請直接在 App 內看 \u003ccode\u003e勝率熱力圖\u003c/code\u003e 與 \u003ccode\u003e完整對照表\u003c/code\u003e，不要依賴此 PDF 做列印或分享。此 PDF 的 \u003ccode\u003eFILE\u003c/code\u003e 刪除為\u003cstrong\u003e永久刪除、不可還原\u003c/strong\u003e，若覺礙眼可請 CEO 協助刪除（刪前會二次確認）。\u003c/p\u003e\n\u003ch2\u003e七、QA 複測資訊\u003c/h2\u003e\n\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e欄位\u003c/th\u003e\u003cth\u003e內容\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\n\u003ctr\u003e\u003ctd\u003e回報時間\u003c/td\u003e\u003ctd\u003e2026-08-28 07:38 UTC（pdf CreationDate \u003ccode class=\"mono\"\u003eD:20260828073848Z\u003c/code\u003e）\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e檔案\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e / \u003ccode class=\"mono\"\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e / \u003ccode class=\"mono\"\u003eFILE_FOLDER 聊天室檔案 6a4b63eb8e9022a22716f09c\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003es3Key\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003eMA item\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e — 6669 緯穎 MA22 53.8% · 日線筆數待補（由 \u003ccode\u003edailyCount\u003c/code\u003e 帶入）\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e插件\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e1094ede45c853958cce864e5\u003c/code\u003e 均線勝率回測 / 視圖 \u003ccode\u003eMaBacktestDetailView\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e期望\u003c/td\u003e\u003ctd\u003e匯出為可列印、可選取的 A4 報告，而非糊掉的截圖\u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e\n\u003cp style=\"margin-top:18px; font-size:12px; color:var(--ink-2); border-top:1px solid var(--hair); padding-top:12px;\"\u003e備註：本頁由 PDF 二進位解包驗證（FlateDecode 解壓 + ToUnicode CMap 對照 + SMask/Transform 量測），非目測臆測。若之後要追此 bug 的修復分支，請以此 FILE id 回放即可重現。\u003c/p\u003e\n\u003c/div\u003e","content":"\u003cdiv class=\"doc\"\u003e  \u003ctable\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e影響插件\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e均線勝率回測\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e1094ede45c853958cce864e5 / MaBacktestDetailView\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e嚴重程度\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e🟡 中\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e功能可用但交付物醜，建議先下架入口\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e案例檔案\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e均線回測 - 6669 緯穎.pdf\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003e52,311 bytes · 1 頁 · A4 595×842\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cp\u003e生成方式\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003epdf.fromHTML + 截圖\u003c/p\u003e\u003c/td\u003e\u003ctd\u003e\u003cp\u003escale 15× · SMask 透明\u003c/p\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e \u003cdiv class=\"callout\"\u003e\u003cspan class=\"tag\"\u003e核心判斷\u003c/span\u003e\u003cdiv style=\"font-size:14px; line-height:1.7; color:var(--ink)\"\u003e這不是缺字或樣式跑版，是\u003cstrong\u003e「互動儀表板被當成文件版所見即所得」\u003c/strong\u003e的選型錯誤：\u003ccode\u003efromHTML\u003c/code\u003e 在 web/mobile 是「抽文字重排」，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e 天生會丟；把熱力圖+表格整塊柵格化成 695×695 圖片再硬縮放，等於同時放棄了文字可選取、自動分頁與中文斷行三個 host 已做好的能力。\u003c/div\u003e\u003c/div\u003e \u003ch2\u003e一、現象重述\u003c/h2\u003e \u003cdiv class=\"compare\"\u003e \u003cdiv class=\"box bad\"\u003e\u003cdiv class=\"label\"\u003e✕ 現在這份 PDF 看起來\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003e頁首三行字正常（標題/日期/CubeLV + 一條灰線），下方大面積空白，左上角一小塊糊掉的色塊。K 線區全白，MA 表格字糊無法複製，無分頁。\u003c/p\u003e\u003c/div\u003e \u003cdiv class=\"box good\"\u003e\u003cdiv class=\"label\"\u003e✓ 報告該長這樣\u003c/div\u003e\u003cp style=\"margin:0;font-size:13px;line-height:1.7\"\u003eA4 多頁文件：推薦 MA22 53.8% 摘要 → 熱力圖文字摘要 → MA15-50 完整對照表（可選取、★ 標 BEST、自動分頁）→ K 線可選附圖 → 參數與免責。\u003c/p\u003e\u003c/div\u003e \u003c/div\u003e \u003cul\u003e \u003cli\u003e熱力圖格子原本是 \u003ccode\u003e\u0026lt;div\u0026gt; grid\u003c/code\u003e，應為文字，現被壓進一張帶 \u003ccode\u003eSMask\u003c/code\u003e 的圖片\u003c/li\u003e \u003cli\u003eK 線是 \u003ccode\u003elightweight-charts\u003c/code\u003e 的 \u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e，\u003ccode\u003efromHTML\u003c/code\u003e 抽字時被直接捨棄\u003c/li\u003e \u003cli\u003e36 列 MA 表從「文字表格」變「圖片」，DPI 又放大 15 倍，印出來糊且不可搜尋\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e二、解包證據（直接讀 PDF 物件）\u003c/h2\u003e \u003cdiv class=\"scroll-hint\"\u003e← 左右滑動查看完整表格 →\u003c/div\u003e\u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e物件\u003c/th\u003e\u003cth\u003e實測值\u003c/th\u003e\u003cth\u003e判讀\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 7 Page\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eMediaBox 595.28×841.89\u003c/code\u003e（A4）\u003c/td\u003e\u003ctd\u003e容器正確\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 8 Contents\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e僅 3 段 \u003ccode\u003eTj\u003c/code\u003e（標題/日期/CubeLV）+ \u003ccode\u003eImage Do\u003c/code\u003e + 一條線\u003c/td\u003e\u003ctd\u003e除了標頭，其他全塞在一張圖裡\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 6 Image\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 RGB / FlateDecode / 14,491,075 bytes\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eDetailView 整塊截圖\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eObj 17 SMask\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e695×695 Gray / Decode [0 1] / mean α 52/255\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e圓角裁切用遮罩，平均半透，邊緣鋸齒\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003eTransform\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1 0 0 1 481.8 743.4 cm\u003c/code\u003e → \u003ccode\u003e15 0 0 15\u003c/code\u003e → \u003ccode\u003eDo\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003cspan class=\"pill pill-red\"\u003e爆版主因\u003c/span\u003e 695×15=10425pt，A4 僅 595pt，95% 在頁外被裁\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003ebbox（α\u0026gt;10）\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e467×568\u003c/code\u003e（x120-587, y64-631）\u003c/td\u003e\u003ctd\u003e有效內容僅約 2/3 張圖，周圍全透明留白\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e字型\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eNotoSansTC Regular/SemiBold CIDFontType2\u003c/code\u003e 正常內嵌\u003c/td\u003e\u003ctd\u003e缺字不是原因，是圖片化\u003c/td\u003e\u003c/tr\u003e \u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e \u003cdiv class=\"codeblock\"\u003eq 1 0 0 1 481.855 743.439 cm 1 0 0 1 0 0 cm 15 0 0 15 0 0 cm   ← 這一行把 695px 圖放大 15 倍 /Image-9750469207 Do Q\u003c/div\u003e \u003cp\u003e\u003cstrong\u003e結論：\u003c/strong\u003eDPI 換算錯誤。可能是把 CSS px 當 pt 直乘，或把「為了 Retina 截 2×」的邏輯疊加到 PDF pt 上，宿主已處理 CJK 字型，插件不該自己再算縮放。\u003c/p\u003e \u003ch2\u003e三、重現步驟\u003c/h2\u003e \u003col\u003e \u003cli\u003e打開 \u003ccode\u003e均線勝率回測\u003c/code\u003e 插件 → 選 \u003ccode\u003e6669 緯穎 MA22 53.8%\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e）\u003c/li\u003e \u003cli\u003e點「匯出 PDF / 下載報告」\u003c/li\u003e \u003cli\u003e檔案庫 \u003ccode\u003e聊天室檔案\u003c/code\u003e 收到 \u003ccode\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e（id \u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e，s3Key \u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e）\u003c/li\u003e \u003cli\u003e打開即見標頭正常、下方空白+糊塊；文字不可選取\u003c/li\u003e \u003c/ol\u003e \u003ch2\u003e四、根因：為何 \u003ccode\u003efromHTML\u003c/code\u003e 不適合這頁\u003c/h2\u003e \u003cul\u003e \u003cli\u003e\u003ccode\u003epdf.fromHTML\u003c/code\u003e 定位是「已有富文本/預覽 HTML 的文件」所見即所得；在 web/mobile 會\u003cstrong\u003e抽文字結構重排\u003c/strong\u003e，\u003ccode\u003e\u0026lt;canvas\u0026gt;\u003c/code\u003e、\u003ccode\u003eShadow DOM\u003c/code\u003e 內容不在抽取範圍內 → K 線直接消失\u003c/li\u003e \u003cli\u003e\u003ccode\u003epdf.fromBlocks\u003c/code\u003e 定位是「結構化資料排版成公文/報告」：標題 + 多區段 + 表格，host 負責 A4 分頁、中文逐字斷行、CJK 內嵌字型，插件只給資料\u003c/li\u003e \u003cli\u003e此頁本質是\u003cstrong\u003e報告\u003c/strong\u003e（推薦 MA、勝率表、參數說明），不是文章。正確選型是後者；前者硬套才會走到「整頁截圖 → SMask → 15×」這條歪路\u003c/li\u003e \u003cli\u003e技能 \u003ccode\u003egenerate-pdf\u003c/code\u003e 明確提醒：\u003cem\u003e不要用 python / 不要自夾字型 / 不要自引 pdf-lib，一律用 \u003ccode\u003e@cubelv/sdk\u003c/code\u003e 的 \u003ccode\u003epdf\u003c/code\u003e\u003c/em\u003e，但也要選對 API\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e五、建議修復\u003c/h2\u003e \u003ch3\u003eP0 — 先止血（今天可做）\u003c/h3\u003e \u003cul\u003e \u003cli\u003e隱藏或灰階 DetailView 的「匯出 PDF」按鈕，改顯示「報告版型重做中」；檔案庫此份醜檔不主動推播\u003c/li\u003e \u003cli\u003e若要保留入口，先彈提示：「目前版型為測試版，建議先用 App 內分享」\u003c/li\u003e \u003c/ul\u003e \u003ch3\u003eP1 — 改用 \u003ccode\u003efromBlocks\u003c/code\u003e 重做（建議版型）\u003c/h3\u003e \u003cdiv class=\"codeblock\"\u003eimport { pdf } from '@cubelv/sdk'; import { saveBlobToDisk } from '@cubelv/sdk'; const blob = await pdf.fromBlocks({ title: `均線回測 - ${stockCode} ${stockName}`, sections: [ { title: '壹、標的與推薦', content: `${stockCode} ${stockName}｜日線 ${dailyCount} 筆｜回測日 ${backtestDate.slice(0,10)}\\n推薦：MA${bestMA} 勝率 ${winRate}%（${tradeCount}次）｜均報 ${avgReturn}%\\n策略：E 策略 收盤突破進 / 1%+肉眼(High\u0026lt;MA×0.99)+二日才出` }, { title: '貳、熱力圖摘要', content: `MA15→MA50 勝率分佈文字摘要（最佳 MA${bestMA} 標 ★，其餘列勝率/次數）` }, { title: '參、完整對照表 MA15-50', content: rows.map(r =\u0026gt; `MA${r.ma}  勝率 ${r.winRate}%  次數 ${r.trades}  均報 ${r.avgReturn}%  最大虧 ${r.maxLoss}%  盤中最大虧 ${r.maxIntra}%  持有 ${r.avgHold}/${r.worstHold}天 ${r.ma===bestMA?'★BEST':''}`).join('\\n') }, { title: '肆、參數與免責', content: `資料源：TWSE STOCK_DAY / Yahoo v8（adjclose 已還原）\\n門檻：勝率 ≥51% 且 \u0026gt;5 次才算 BEST；放棄門檻 \u0026gt;50日無符合\\n免責：歷史回測僅供參考，不構成投資建議` }, ], }); await saveBlobToDisk(blob, `均線回測 - ${stockCode} ${stockName}.pdf`, 'application/pdf'); // K 線如需附圖：canvas.toDataURL() 轉 \u0026lt;img\u0026gt; 插在最後一段，勿整頁截圖\u003c/div\u003e \u003cul\u003e \u003cli\u003e好處：文字可選取、可搜尋、自動分頁、中文不會被切字、中文字型由 host 統一內嵌\u003c/li\u003e \u003cli\u003e表格 36 列用等寬文字排版，host 會自動跨頁，不會糊\u003c/li\u003e \u003cli\u003eK 線如要保留，用 \u003ccode\u003ecanvas.toDataURL('image/png')\u003c/code\u003e 單獨轉一張適當 DPI 的圖插在最後一頁即可\u003c/li\u003e \u003c/ul\u003e \u003ch3\u003eP2 — 品質門檻\u003c/h3\u003e \u003cul\u003e \u003cli\u003e新增前後對比截圖驗收：文字可選取、A4 邊距 56pt 內不溢出、無 15× 放大\u003c/li\u003e \u003cli\u003e補一個 36 列長表的分頁測試（確保第二頁表頭重複或至少可讀）\u003c/li\u003e \u003c/ul\u003e \u003ch2\u003e六、當前規避（給使用者）\u003c/h2\u003e \u003cp\u003e在改版前，請直接在 App 內看 \u003ccode\u003e勝率熱力圖\u003c/code\u003e 與 \u003ccode\u003e完整對照表\u003c/code\u003e，不要依賴此 PDF 做列印或分享。此 PDF 的 \u003ccode\u003eFILE\u003c/code\u003e 刪除為\u003cstrong\u003e永久刪除、不可還原\u003c/strong\u003e，若覺礙眼可請 CEO 協助刪除（刪前會二次確認）。\u003c/p\u003e \u003ch2\u003e七、QA 複測資訊\u003c/h2\u003e \u003cdiv class=\"wrap\"\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e欄位\u003c/th\u003e\u003cth\u003e內容\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e \u003ctr\u003e\u003ctd\u003e回報時間\u003c/td\u003e\u003ctd\u003e2026-08-28 07:38 UTC（pdf CreationDate \u003ccode class=\"mono\"\u003eD:20260828073848Z\u003c/code\u003e）\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e檔案\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a913c2cc31ee4749f0de4d1\u003c/code\u003e / \u003ccode class=\"mono\"\u003e均線回測 - 6669 緯穎.pdf\u003c/code\u003e / \u003ccode class=\"mono\"\u003eFILE_FOLDER 聊天室檔案 6a4b63eb8e9022a22716f09c\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003es3Key\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003euploads/6a3dcfc700e9b9fd06d5ef/2e73c79d-7d4b-48bd-bbd5-9ed6ce0424b0.pdf\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003eMA item\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e6a90f2863622845634546be1\u003c/code\u003e — 6669 緯穎 MA22 53.8% · 日線筆數待補（由 \u003ccode\u003edailyCount\u003c/code\u003e 帶入）\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e插件\u003c/td\u003e\u003ctd\u003e\u003ccode class=\"mono\"\u003e1094ede45c853958cce864e5\u003c/code\u003e 均線勝率回測 / 視圖 \u003ccode\u003eMaBacktestDetailView\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e \u003ctr\u003e\u003ctd\u003e期望\u003c/td\u003e\u003ctd\u003e匯出為可列印、可選取的 A4 報告，而非糊掉的截圖\u003c/td\u003e\u003c/tr\u003e \u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e \u003cp style=\"margin-top:18px; font-size:12px; color:var(--ink-2); border-top:1px solid var(--hair); padding-top:12px;\"\u003e備註：本頁由 PDF 二進位解包驗證（FlateDecode 解壓 + ToUnicode CMap 對照 + SMask/Transform 量測），非目測臆測。若之後要追此 bug 的修復分支，請以此 FILE id 回放即可重現。\u003c/p\u003e \u003c/div\u003e","createdAt":1787903716010,"deletedAt":null,"displayMode":"artifact","embedRenders":{},"id":"c05656c14441f7ff0679f2e7","isNew":false,"isPublic":true,"itemType":"NOTE","name":"CubeLV 平台 Bug 回報：均線回測 PDF 用截圖直出，版面爆版且字糊 — 6669 緯穎案例","parents":{"4465d0a863da5d1b345d888c":1787903716010},"preParentID":null,"updatedAt":1788205268080,"updatedBy":{"userId":"6a3dcfc700e9b9fd06d5ef","userName":"蔡其樺"},"version":12}]}