轉換流程
本頁說明 convert() 如何把 PDF 頁面渲染成圖片,以及解析度、輸出格式與失敗時的實際行為。
流程
- 設定
pdfjsLib.GlobalWorkerOptions.workerSrc為 cdnjs 上的 pdf.worker.js - 以
getDocument()解析file,CMap 從 cdnjs 取得(處理 CJK 等字型編碼) - 解析成功後在
<body>附加進度遮罩 - 所有頁面同時建立
canvas並渲染,每完成一頁就把 Data URL 推入結果陣列並更新進度 - 全部完成後延遲 500ms,resolve 結果陣列並移除遮罩
解析度:scale
輸出像素尺寸 = PDF 頁面尺寸(pt)× scale。預設 1.5;US Letter(612×792 pt)在 scale: 1 時輸出 612×792,在預設值時輸出 918×1188。
<script>
const sample = async () => (await fetch("/assets/sample.pdf")).arrayBuffer();
const size = src => new Promise(r => {
const img = new Image();
img.onload = () => r(img.width + "x" + img.height);
img.src = src;
});
addEventListener("load", async () => {
for (const scale of [0.5, 1, 1.5]) {
const [first] = await new pdf2image({ file: await sample(), type: "png", scale }).convert();
console.log("scale", scale, "->", await size(first));
}
});
</script>
輸出格式:type
type 只接受 png、jpg、webp,其他值回退為 jpg。結果由 canvas.toDataURL("image/" + type) 產生,因此:
type |
傳給 toDataURL |
實際輸出 |
|---|---|---|
png |
image/png |
PNG |
webp |
image/webp |
WebP(瀏覽器不支援時為 PNG) |
jpg(預設) |
image/jpg |
PNG:瀏覽器只認 image/jpeg,不認得的 MIME 一律回退 PNG |
也就是說,目前版本無法輸出 JPEG,預設值實際得到的是 PNG。
<script>
addEventListener("load", async () => {
for (const type of ["png", "jpg", "webp", "gif"]) {
const buffer = await (await fetch("/assets/sample.pdf")).arrayBuffer();
const [first] = await new pdf2image({ file: buffer, type, scale: 0.5 }).convert();
console.log(type.padEnd(4), "->", first.slice(0, first.indexOf(";")));
}
});
</script>
結果順序
頁面是併發渲染,結果在「每頁完成時」依序推入陣列,而非依頁碼寫入對應位置。頁面複雜度差異大時,images[0] 不保證是第 1 頁。
file 只能用一次
pdf.js 會把傳入的 ArrayBuffer 轉移(transfer)給 worker,轉換後原 buffer 的 byteLength 變成 0。因此:
- 同一個實例第二次呼叫
convert()會以TypeErrorreject,訊息為「Cannot perform Construct on a detached ArrayBuffer」;已轉換的images不受影響 - 同一個 buffer 不能再交給另一個實例;需要重轉時重新讀取檔案
<script>
addEventListener("load", async () => {
const buffer = await (await fetch("/assets/sample.pdf")).arrayBuffer();
const converter = new pdf2image({ file: buffer, type: "png", scale: 0.5 });
console.log("first:", (await converter.convert()).length, "pages");
console.log("buffer byteLength:", buffer.byteLength);
try {
await converter.convert();
} catch (err) {
console.log("second:", String(err));
}
console.log("images kept:", converter.images.length);
});
</script>
失敗行為
| 情境 | reject 的值 |
|---|---|
未提供 file |
字串 "error The PDF file is empty, i.e. its size is zero bytes." |
| 不是有效的 PDF | 字串 "error Invalid PDF structure." |
| 頁面渲染失敗 | 字串 "error i is not defined":錯誤處理引用了不存在的變數,原始錯誤訊息遺失 |
| 重複使用已轉移的 buffer | TypeError 物件 |
| pdf.js 尚未載入 | ReferenceError 物件(見 核心概念) |
reject 值有字串也有 Error,以 String(err) 處理可涵蓋兩者。pdf.js 載入失敗時,套件本身也會呼叫 console.error("error", err)。
<script>
addEventListener("load", async () => {
const cases = { "no file": {}, "not a pdf": { file: new TextEncoder().encode("hello").buffer } };
for (const [name, options] of Object.entries(cases)) {
try {
await new pdf2image(options).convert();
} catch (err) {
console.log(name, "->", typeof err, String(err));
}
}
});
</script>