📋
PDF.js(pdfjs-dist) / react-pdfで日本語の文字が表示されない問題の解決方法
原因
cMapという、PDFに保存されている文字コードとフォントの文字データを紐付けるファイルが不足していることが原因です。
CDNを使う方法
PDF.js の場合
以下のようにCDNからcMapを読み込むことで表示されるようになります。
pdf-utils.ts
import * as pdfjs from "pdfjs-dist";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.js",
import.meta.url,
).toString();
export async function loadPDF(path: string): Promise<pdfjs.PDFPageProxy[]> {
const loadingTask = pdfjs.getDocument({
url: path,
+ cMapUrl: "https://unpkg.com/pdfjs-dist@${pdfjs.version}/cmaps/",
+ cMapPacked: true,
});
const pdf = await loadingTask.promise;
const pages = [];
for (let i = 0; i < pdf.numPages; i++) {
pages.push(await pdf.getPage(i + 1));
}
return pages;
}
react-pdfの場合
pdf-viewer.tsx
<Document
file={pdfPath}
+ options={{
+ cMapUrl: "https://unpkg.com/pdfjs-dist@${pdfjs.version}/cmaps/",
+ cMapPacked: true,
+ }}
>
静的アセットを読み込む方法(おすすめ)
あるいはビルドする前にnode_modulesからコピーして使う方法も考えられます。
package.json
{
"name": "hoge",
"license": "UNLICENSED",
"version": "1.0.0",
"private": true,
"scripts": {
+ "build": "npm run copy-cmaps && next build",
+ "copy-cmaps": "cp -r node_modules/pdfjs-dist/cmaps/ public/cmaps/",
"dev": "next dev",
"lint": "next lint",
"lint:fix": "next lint --fix",
"start": "next start",
"type-check": "tsc --noEmit"
Next.jsやRemixなどの場合は public/
配下に静的アセットとして保存して参照します。
PDF.js の場合
pdf-utils.ts
import * as pdfjs from "pdfjs-dist";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.js",
import.meta.url,
).toString();
export async function loadPDF(path: string): Promise<pdfjs.PDFPageProxy[]> {
const loadingTask = pdfjs.getDocument({
url: path,
+ cMapUrl: `/cmaps/`,
+ cMapPacked: true,
});
const pdf = await loadingTask.promise;
const pages = [];
for (let i = 0; i < pdf.numPages; i++) {
pages.push(await pdf.getPage(i + 1));
}
return pages;
}
react-pdfの場合
pdf-viewer.tsx
<Document
file={pdfPath}
+ options={{
+ cMapUrl: "/cmaps/",
+ cMapPacked: true,
+ }}
>
Discussion