訂判斷及所需輸入
固定內文在每頁可用八十毫米時共兩頁。留所需頁尾空間後,可用高變七十,最終 PDF 成三頁。照用早前總數二就出現 Page 3 of 2,更正須跟最後頁數。
| 情況 | 輸入 JSON |
|---|---|
| 原例測試 | {"footerRequired":true} |
跑所附比較
瀏覽器生成最終 PDF,抽字逐頁核頁尾,不用估計內文頁數代替排版後結果。CSS 頁計數只在此引擎實測,未承諾所有呈現器一致。
| 路徑 | 輸出 JSON |
|---|---|
| 錯誤路徑 | {"pageCount":3,"footers":["Page 1 of 2","Page 2 of 2","Page 3 of 2"]} |
| 所需路徑 | {"pageCount":3,"footers":["Page 1 of 3","Page 2 of 3","Page 3 of 3"]} |
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {pathToFileURL} from 'node:url';
const htmlEscape=s=>String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
async function withPage(action,options={}){
const require=createRequire(import.meta.url);const {chromium}=require('playwright');
const browser=await chromium.launch({headless:true});
try{const context=await browser.newContext(options);const page=await context.newPage();
const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
return await action(page,context,requests);
}finally{await browser.close();}
}
async function pdfObservation(html){
const bytes=await withPage(async page=>{await page.setContent(html);return page.pdf({preferCSSPageSize:true,printBackground:true});});
const require=createRequire(import.meta.url);
const {getDocument}=await import(pathToFileURL(require.resolve('pdfjs-dist/legacy/build/pdf.mjs')).href);
const loadingTask=getDocument({data:Uint8Array.from(bytes),useSystemFonts:true,disableFontFace:true});
try{const document=await loadingTask.promise;const pages=[];for(let n=1;n<=document.numPages;n++){
const page=await document.getPage(n);const content=await page.getTextContent();
pages.push(content.items.filter(x=>typeof x.str==='string'&&x.str).map(x=>({text:x.str,x:x.transform[4],y:x.transform[5]})));
}return {pageCount:document.numPages,pages};}finally{await loadingTask.destroy();}
}
const printStyle='<style>@page{size:100mm 100mm;margin:10mm}body{margin:0;font:10px Arial}p{margin:0}</style>';
const run=async function run(i,corrected=true){
if(typeof i.footerRequired!=='boolean')return {held:true};
const footer=i.footerRequired?'@page{margin-bottom:20mm;@bottom-center{content:"Page " counter(page) " of " '+(corrected?'counter(pages)':'"2"')+';font:10px Arial}}':'';
const html=printStyle+'<style>'+footer+'.body{height:160mm}.line{height:10mm;line-height:10mm}</style><div class="body">'+Array.from({length:16},(_,n)=>'<p class="line">LINE'+(n+1)+'</p>').join('')+'</div>';
const out=await pdfObservation(html);return {pageCount:out.pageCount,footers:out.pages.map(p=>p.map(x=>x.text).find(s=>s.startsWith('Page '))??null)};
};
const cases=[{"input":{"footerRequired":true},"corrected":false,"expected":{"pageCount":3,"footers":["Page 1 of 2","Page 2 of 2","Page 3 of 2"]}},{"input":{"footerRequired":true},"corrected":true,"expected":{"pageCount":3,"footers":["Page 1 of 3","Page 2 of 3","Page 3 of 3"]}},{"input":{"footerRequired":false},"corrected":true,"expected":{"pageCount":2,"footers":[null,null]}},{"input":{"footerRequired":null},"corrected":true,"expected":{"held":true}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
按邊界依據作判斷
沒有該頁尾空間要求,內文仍兩頁且無頁尾;要求未知便先停。
- 先留所需頁尾空間
- 生成最後排版
- 逐頁核總頁數
不能把未加頁尾前的頁數帶到最終文件。
| 條件 | 輸入 JSON | 預期輸出 JSON |
|---|---|---|
| 內文毋須留頁尾位 | {"footerRequired":false} | {"pageCount":2,"footers":[null,null]} |
| 頁尾要求未知 | {"footerRequired":null} | {"held":true} |
原例最後三個頁尾應寫甚麼?
查看參考答案
依次 Page 1 of 3、Page 2 of 3、Page 3 of 3,都是同一份最終三頁檔案。