MuPDF
usage
JS libraryはwasmとしてnpmに公開されている
wasmが8MBくらいあって草
pdf.jsの代わりとしてそのまま使えそうtakker.icon 自力でpdf parser作る必要なさそうかも
とりあえず、テキスト抽出とページ描画を試してみる
テキスト抽出
2024-10-29 23:39:49 問題なし
code:text.ts
import { Document } from "npm:mupdf@0.3";
const pdfPath = "sample.pdf";
const pdfData = await Deno.readFile(pdfPath);
const pdfDocument = Document.openDocument(pdfData, "application/pdf");
const index = pdfDocument.countPages();
for (let i = 0; i < index; i++) {
const page = pdfDocument.loadPage(i);
const text = page.toStructuredText();
console.log(text.asText());
}
描画
2024-10-29 23:44:52 問題なし
code:render.ts
import { ColorSpace, Document } from "npm:mupdf@0.3";
const pdfPath = "sample.pdf";
const pdfData = await Deno.readFile(pdfPath);
const pdfDocument = Document.openDocument(pdfData, "application/pdf");
const index = pdfDocument.countPages();
for (let i = 0; i < index; i++) {
const page = pdfDocument.loadPage(i);
const z = 1.5 * 96 / 72;
await Deno.writeFile(page-${i}.png, png);
}
画像の抽出
2024-10-30 00:13:09 できた
code:image.ts
import { Document } from "npm:mupdf@0.3";
const pdfPath = "sample.pdf";
const pdfData = await Deno.readFile(pdfPath);
const pdfDocument = Document.openDocument(pdfData, "application/pdf");
const index = pdfDocument.countPages();
let count = 0;
for (let i = 0; i < index; i++) {
const page = pdfDocument.loadPage(i);
const text = page.toStructuredText("preserve-images");
text.walk({
onImageBlock(_, _2, image) {
Deno.writeFileSync(png-${count++}.png, image.toPixmap().asPNG());
},
});
if (count > 5) break;
}
2024-10-30 00:19:50 成功
OutlineItem.uriにはURL fragmentでページ番号が、URL query paramtersでzoom settingsが渡される
code:outline.ts
import { Document } from "npm:mupdf@0.3";
const pdfPath = "sample.pdf";
const pdfData = await Deno.readFile(pdfPath);
const pdfDocument = Document.openDocument(pdfData, "application/pdf");
const outlines = pdfDocument.loadOutline();
type OutlineItem = Exclude<ReturnType<Document"loadOutline">, null> extends (infer T) ? T : never;
function* crawl(
outlines: Iterable<OutlineItem>,
depth = 0,
): Generator<string, void, unknown> {
for (const outline of outlines) {
yield ${" ".repeat(depth)}${outline.title}: ${outline.uri};
yield* crawl(outline.down ?? [], depth + 1);
}
}
for (const line of crawl(outlines ?? [])) {
console.log(line);
}
wasmのload方法をカスタムするには、js codeに手を加える必要あり
mupdf.tsとmupdf-wasm.jsとmupdf-wasm.d.tsを書き換えればいい