åæ
ãã®èšäºã§ã¯ä»¥äžãåæãšããŠããŸãã
- Next.js ã®ããŒãžã§ã³ã¯ 13.4.19 (App router 䜿çš)
- Typescript 䜿çš
pdf-lib
ã䜿çš- Tailwind ã䜿çš
- æ¬çªç°å¢ã«å¿ èŠãªãšã©ãŒãã³ããªã³ã°ãããªããŒã·ã§ã³ãªã©ã¯å®è£ ããŠããªã
ãã®èšäºã®ãŽãŒã«
以äžã®ããã«ããPDF ããŠã³ããŒãããšãããã¿ã³ãã¯ãªãã¯ãããšãæå®ãã PDF ãã¡ã€ã«ããã³ãã¬ãŒããšããŠãããŒã¿ãè¿œèšãã PDF ãã¡ã€ã«ãããŠã³ããŒããããŸãã ãã³ãã¬ãŒããšããŠäœ¿çšãã PDF ãã¡ã€ã«ã¯ãA4 ãµã€ãºã§ããŒãžäžå€®ã«ãSample PDFããšæžãããŠãããã®ã§ãã ããã«ãæ¥æ¬èª æžã蟌㿠ãã¹ã PDFããšããé©åœãªæååãæžã蟌ã¿ãããŠã³ããŒãããŠããŸãã
ããªãã¡ã以äžã®æ©èœã®å®è£ ã«ã€ããŠè§£èª¬ããŸãã
- 奜ã㪠PDF ãã¡ã€ã«ããã³ãã¬ãŒããšããŠäœ¿çšããŠããã® PDF ãã¡ã€ã«ã«ä»»æã®ããŒã¿ãæžã蟌ã
- ãã³ãã¬ãŒãã«ããŒã¿ãæžã蟌ãã PDF ãã¡ã€ã«ãçæããããŠã³ããŒããã
pdf-lib ãã€ã³ã¹ããŒã«ãã
PDF ãã¡ã€ã«ã«ããŒã¿ãæžã蟌ãããã«ãpdf-lib
ã䜿çšããŸããpdf-lib
ã§ã¯ PDF ãã¡ã€ã«ã®æ°èŠäœæãããŒã¿ã®æžã蟌ã¿ãããŒãžè¿œå ãåé€ãªã©è²ã
㪠PDF æäœãå¯èœãªããã±ãŒãžã«ãªããŸãã
ãŸããæ¥æ¬èªãã©ã³ããæ±ãããã«@pdf-lib/fontkit
ãäžç·ã«ã€ã³ã¹ããŒã«ããŸãã
# npmã䜿ãå Žå
npm install --save pdf-lib @pdf-lib/fontkit
# yarnã䜿ãå Žå
yarn add pdf-lib @pdf-lib/fontkit
pdf-lib
ã®å
¬åŒãªããžããªã¯ä»¥äžã§ãã
@pdf-lib/fontkit
ã®å
¬åŒãªããžããªã¯ä»¥äžã§ãã
䜿çšããæ¥æ¬èªãã©ã³ããçšæãã
ããã§ã¯ãåçšå©çšãå¯èœãªæ¥æ¬èªãã©ã³ããšããŠä»¥äžã® IPA ãã©ã³ãã䜿çšããŸãã
ãã©ã³ããã¡ã€ã«ãããŠã³ããŒãããNext.js ã®public/fonts
ã«é
眮ããŸããfonts
ãã£ã¬ã¯ããªã¯ããã©ã«ãã§ã¯çšæãããŠããªããããå¿
èŠã«å¿ããŠäœæããŠãã ããã
public
çŽäžã«fonts
ãã£ã¬ã¯ããªãäœæãããã®äžã«ipaexm.ttf
ãé
眮ããå Žåã¯ä»¥äžã®ããã«ãªããŸãã
public
âââ fonts
â âââ ipaexm.ttf
ç¹ã«ãã©ã³ãã®é çœ®å Žæã«ã€ããŠã¯æ±ºãŸãã¯ãªãã®ã§ãå¿ èŠã«å¿ããŠé©åãªå Žæã«é 眮ããŠãã ããã
PDF ãã¡ã€ã«ãåºåçšã®ãã¿ã³ãäœæãã
PDF ãã¡ã€ã«åºåçšã®ãã¿ã³ã®ã³ã³ããŒãã³ãPdfPrintButton.tsx
ã以äžã®ããã«ããŸãã
'use client';
import { PDFDocument } from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';
export default function PdfPrintButton() {
const pdfPrint = async () => {
// Create a new PDFDocument
const pdfDoc = await PDFDocument.create();
// ãã³ãã¬ãŒããšããŠäœ¿çšãããPDFãèªã¿èŸŒã
const url = '/a4_sample.pdf';
const arrayBuffer = await fetch(url).then((res) => res.arrayBuffer());
const doc = await PDFDocument.load(arrayBuffer);
// fontã®èªã¿èŸŒã¿ãšåã蟌ã¿
pdfDoc.registerFontkit(fontkit);
const fontRaw = await fetch('/fonts/ipaexm.ttf').then((res) =>
res.arrayBuffer(),
);
const fontIpamp = await pdfDoc.embedFont(new Uint8Array(fontRaw), {
subset: true,
});
// ãã³ãã¬ãŒããã¡ã€ã«ã®ïŒããŒãžç®ãã³ããŒããŠãæ°ããããŒãžãäœæãã
const [_templatePage] = await pdfDoc.copyPages(doc, [0]);
const _page1 = pdfDoc.addPage(_templatePage);
// æžã蟌ãæååã®äœçœ®ããµã€ãºèšå®
const targetText = 'æ¥æ¬èª æžã蟌㿠ãã¹ã PDF';
const targetTextFontSize = 18;
const targetTextXPosition = 200;
const targetTextYPosition = 800;
// æžã蟌ãæååã®äœçœ®ããµã€ãºããã©ã³ããè²ãæå®ããŠæžã蟌ã
// æ¥æ¬èªãæžã蟌ãå Žåã«ã¯ãã©ã³ãã®èšå®ãå¿
èŠ
_page1.drawText(targetText, {
x: targetTextXPosition,
y: targetTextYPosition,
size: targetTextFontSize,
font: fontIpamp,
// color: rgb(0, 0, 0)
});
const dataUri = await pdfDoc.saveAsBase64({
dataUri: true,
addDefaultPage: false,
});
// æžã蟌ã¿ããPDFãã¡ã€ã«ãããŠã³ããŒãããããã®ãªã³ã¯ãäœæãã
// ãã®ãªã³ã¯ãã¯ãªãã¯ããããšã§ããŠã³ããŒãã§ããããã«ãã
const link = document.createElement('a');
link.href = dataUri;
link.download = 'ãµã³ãã«.pdf';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return (
<>
<button
className='bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2 rounded bg-blue-500 hover:bg-blue-700 mr-2'
onClick={() => pdfPrint()}
>
<span>PDFããŠã³ããŒã</span>
</button>
</>
);
}
äžèšã®PdfPrintButton
ããäŸãã°ä»¥äžã®ããã«é©åœãªããŒãžã®äžã§èªã¿èŸŒãã§äœ¿çšããŸãã
import PdfPrintButton from './components/PdfPrintButton';
export default function Home() {
return (
<main className='flex min-h-screen flex-col items-center justify-between p-24'>
<div className='z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex'>
<PdfPrintButton />
</div>
</main>
);
}
ããšã¯ä»¥äžã§ãµãŒããŒãèµ·åããŠãPDFããŠã³ããŒã
ãã¿ã³ãã¯ãªãã¯ãããšãåé ã«èŒãã GIF ç»åãšåãããã«ãµã³ãã«.pdf
ãšãããã¡ã€ã«ãããŠã³ããŒããããŸãã
yarn dev
æ¥æ¬èªã®åãæ±ãã«ã€ããŠ
pdf-lib
ã䜿çšã㊠PDF ãã¡ã€ã«ã«æ¥æ¬èªãæžã蟌ã¿ããå Žåã¯ãæ¥æ¬èªãã©ã³ããèªã¿èŸŒãã§åã蟌ãå¿
èŠããããŸãã
æ¥æ¬èªãæžã蟌ãéã«æ¥æ¬èªãã©ã³ããæå®ãããŠããªãå Žåã¯ãããŠã³ããŒããã¿ã³ãã¯ãªãã¯ããæã«ãã©ãŠã¶åŽã«ä»¥äžã®ãããªãšã©ãŒãåºãŸãã
Uncaught (in promise) Error: WinAnsi cannot encode "ã" (0x30c6)
äžèšã«èŒããPdfPrintButton.tsx
ã®äžã§æ¥æ¬èªãã©ã³ãã®èªã¿èŸŒã¿ãšåã蟌ã¿éšåã¯ä»¥äžã«ãªããŸãã
ãµãã»ããåã«å¯Ÿå¿ããŠãããã©ã³ããã¡ã€ã«ã§ããã°ã以äžã®ããã«subset: true
ãæå®ããããšã§ãµãã»ããåããããšãã§ããŸãã
'use client';
import { PDFDocument } from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';
export default function PdfPrintButton() {
const pdfPrint = async () => {
(...çç¥...)
// fontã®èªã¿èŸŒã¿ãšåã蟌ã¿
pdfDoc.registerFontkit(fontkit);
const fontRaw = await fetch('/fonts/ipaexm.ttf').then((res) =>
res.arrayBuffer(),
);
const fontIpamp = await pdfDoc.embedFont(new Uint8Array(fontRaw), {
subset: true,
});
(...çç¥...)
};
ãªããæ¥æ¬èªãã¡ã€ã«ã®èšçœ®ãªã©ã¯äœ¿çšããæ¥æ¬èªãã©ã³ããçšæããã®éãã§ãã
æžã蟌ã¿äœçœ®ã®èª¿æŽã«ã€ããŠ
drawText
ã§æå®ããx
ïŒæ°Žå¹³äœçœ®ïŒããã³y
ïŒçžŠäœçœ®ïŒã®å€ãå®éã«ã©ãã«æžã蟌ãŸãããã¯ããã³ãã¬ãŒããšããŠäœ¿çšãããã¡ã€ã«ã®è§£å床ã«äŸåããŸãã
äŸãã°ãä»å䜿çšããa4_sample.pdf
ãã¡ã€ã«ã®è§£å床ã¯595âÃâ841
ã§ããïŒè§£å床ã¯ãã¡ã€ã«äžã§å³ã¯ãªãã¯ããŠãæ
å ±ãã®ãããªé
ç®ãã確èªã§ãããšæããŸããïŒ
pdf-lib
ã¯ããã¡ã€ã«ã®å·Šäžãåºç¹ïŒx
ã 0ãy
ã 0ïŒãšãããããa4_sample.pdf
ã®äžéšã«æžã蟌ã¿ããå Žåã¯ä»¥äžã®ããã«æå®ããŸãã
_page1.drawText('TEST PDF', {
x: 290,
y: 830,
size: 18,
// font: fontIpamp,
// color: rgb(0, 0, 0)
});
äžèšã®drawText
ã§ã¯ãa4_sample.pdf
ã®å·Šäžãã 290px å³ã830px äžã®äœçœ®ã«TEST PDF
ãšæžã蟌ã¿ãŸãã
äžå€®æãã§æžã蟌ã
drawText
ã®x
ãy
ã¯æååã®æžãå§ãäœçœ®ãæå®ãããããæååã®é·ãã«å¿ããŠäžå€®æããããå Žåã¯ä»¥äžã®ããã«ããŸãã
(...çç¥...)
// fontã®èªã¿èŸŒã¿ãšåã蟌ã¿
pdfDoc.registerFontkit(fontkit);
const fontRaw = await fetch('/fonts/ipaexm.ttf').then((res) =>
res.arrayBuffer(),
);
const fontIpamp = await pdfDoc.embedFont(new Uint8Array(fontRaw), {
subset: true,
});
(...çç¥...)
const targetText = 'äžå€®æããã¹ã';
const targetTextFontSize = 18;
const targetTextYPosition = 800;
// 䜿çšãããã©ã³ãã§ã®æååã®é·ããååŸ
const targetTextWidth = fontIpamp.widthOfTextAtSize(
targetText,
targetTextFontSize,
);
// äžå€®æãããããã®ïœã®åº§æšãèšç®
const targetTextXPosition = page.getWidth() / 2 - targetTextWidth / 2;
_page1.drawText(targetText, {
x: targetTextXPosition,
y: targetTextYPosition,
size: targetTextFontSize,
font: fontIpamp,
// color: rgb(0, 0, 0)
});
äžèšã¯ããã©ã³ãã®ãµã€ãºãæå®ããŠæååã®é·ãtargetTextWidth
ãååŸããäžå€®æããããèŠçŽ ã®å¹
ïŒäžèšã§ã¯ãããŒãžã®å¹
ïŒã®ååããæååã®é·ãã®ååãåŒããå€ãx
ãšããŠæå®ããŠããŸãã
ããã«ããæååã®é·ãã«ãããããŒãžäžå€®ã«æååãæžãããããšãã§ããŸãã
ããããŒãžäžå€®ã§ã¯ãªããç¹å®ã®èŠçŽ ã®äžã§äžå€®æããããå Žåã¯ããã®èŠçŽ ã®å¹ ãæå®ãããªã©èª¿æŽããã°å¯èœã§ãã
ééãããšã©ãŒ
Error: Failed to parse PDF document (line:0 col:xxxx offset=xxxx): No PDF header found
ããã¯ãèªã¿èŸŒãããšããŠãããã³ãã¬ãŒããšããŠäœ¿çšããããã® PDF ãã¡ã€ã«ãååšããªãã£ãå Žåã«çºçããŸããã
ãã©ãŠã¶ã®ã³ã³ãœãŒã«ã«è¡šç€ºãããŸãã
å
·äœçã«ã¯ã以äžã®url
ãééã£ãŠããããã« PDF ãèªã¿èŸŒããªãç¶æ
ã§ãããé©å㪠URL ã«å€æŽããããšã§è§£æ¶ã§ããŸããã
const pdfDoc = await PDFDocument.create();
// ãã³ãã¬ãŒããšããŠäœ¿çšãããPDFãèªã¿èŸŒã
const url = '/a4_sample.pdf';
// 以äžã®ããã«ç°å¢å€æ°ã䜿ã£ãŠããå Žåã¯ãã®ç°å¢å€æ°ã®å€ãééã£ãŠããå¯èœæ§ããããããããŸãã
// const url = `${process.env.NEXT_PUBLIC_URL}/a4_sample.pdf`;
const arrayBuffer = await fetch(url).then((res) => res.arrayBuffer());
const doc = await PDFDocument.load(arrayBuffer);
ãŸãšã
pdf-lib
ã䜿çšããããšã§ã奜ã㪠PDF ãã¡ã€ã«ããã³ãã¬ãŒããšããŠããŒã¿ãæžã蟌ãããšãã§ããŸãã
ãã®èšäºã§ã¯ïŒã€ã®ãã³ãã¬ãŒããã¡ã€ã«ã«æååãæžã蟌ãã§ïŒã€ã®æ°ãã PDF ãã¡ã€ã«ãããŠã³ããŒãããã®ã¿ã®ç°¡åãªäŸã§ããã
ããšã¯ããŒã¿äžèŠ§ããç¹°ãè¿ãåŠçããããè€æ°ã®ãã³ãã¬ãŒãã«ããŒã¿ãæžã蟌ãã ããè²ã
ãªããšãã§ãããšæããŸãã