我試圖用來PDFKit生成一個簡單的 pdf,在大多數情況下 pdf 可以作業,但盡管以一種非常無用的方式,我所擁有的是一個甲板構建 API,它接收許多卡片,我想匯出這些物件中的每一個對于 pdf,它就像顯示他們的名字一樣簡單,但事實上,pdf 一次只呈現一張卡片,而且只在一行上,id 喜歡發生的事情是讓它將文本分成列,所以 itd看起來與此類似。
column 1 | column 2
c1 c8
c2 c9
c3 c10
c4 c(n)
到目前為止,這是我的代碼,
module.exports = asyncHandler(async (req, res, next) => {
try {
// find the deck
const deck = await Deck.findById(req.params.deckId);
// need to sort cards by name
await deck.cards.sort((a, b) => {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
} else {
return 0;
}
});
// Create a new PDF document
const doc = new PDFDocument();
// Pipe its output somewhere, like to a file or HTTP response
doc.pipe(
fs.createWriteStream(
`${__dirname}/../../public/pdf/${deck.deck_name}.pdf`
)
);
// Embed a font, set the font size, and render some text
doc.fontSize(25).text(`${deck.deck_name} Deck List`, {
align: "center",
underline: true,
underlineColor: "#000000",
underlineThickness: 2,
});
// We need to create two columns for the cards
// The first column will be the card name
// The second column will continue the cards listed
const section = doc.struct("P");
doc.addStructure(section);
for (const card of deck.cards) {
doc.text(`${card.name}`, {
color: "#000000",
fontSize: 10,
columns: 2,
columnGap: 10,
continued: true,
});
}
section.end();
// finalize the PDF and end the response
doc.end();
res.status(200).json({ message: "PDF generated successfully" });
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: `Server Error - ${error.message}`,
});
}
});
目前,這確實會生成我想要的列順序,但是對這個解決方案有一個極端的警告,也就是說,如果卡片文本不是很長,下一張卡片將從同一行開始,如果我能找到一種方法讓文本占據該行的整個寬度,但我還沒有看到任何與此相關的內容。
uj5u.com熱心網友回復:
我認為問題在于您依賴于 PDFKit 的文本“流”API/邏輯,并且當兩張卡片不足以流過您的列并且您在一列中獲得兩張卡片時,您會遇到問題。
我想說的是,您真正想要的是根據您的初始文本樣本創建一個表格。
PDFKit 還沒有表格 API,因此您必須自己撰寫一個。
這是一種計算事物維度的方法:
- 頁面大小
- 文本單元格的大小(您可以自己手動選擇,或者使用 PDFKit 告訴您某段文本有多大)
- 邊距
然后,您使用這些大小來計算您的頁面可以容納多少行和多少列文本。
最后,您遍歷每頁的列和行,將文本逐行寫入“坐標”(我通過“偏移量”跟蹤并用于計算最終的“位置”)。
const PDFDocument = require('pdfkit');
const fs = require('fs');
// Create mock-up Cards for OP
const cards = [];
for (let i = 0; i < 100; i ) {
cards.push(`Card ${i 1}`);
}
// Set a sensible starting point for each page
const originX = 50;
const originY = 50;
const doc = new PDFDocument({ size: 'LETTER' });
// Define row height and column widths, based on font size; either manually,
// or use commented-out heightOf and widthOf methods to dynamically pick sizes
doc.fontSize(24);
const rowH = 50; // doc.heightOfString(cards[cards.length - 1]);
const colW = 150; // doc.widthOfString(cards[cards.length - 1]); // because the last card is the "longest" piece of text
// Margins aren't really discussed in the documentation; I can ignore the top and left margin by
// placing the text at (0,0), but I cannot write below the bottom margin
const pageH = doc.page.height;
const rowsPerPage = parseInt((pageH - originY - doc.page.margins.bottom) / rowH);
const colsPerPage = 2;
var cardIdx = 0;
while (cardIdx < cards.length) {
var colOffset = 0;
while (colOffset < colsPerPage) {
const posX = originX (colOffset * colW);
var rowOffset = 0;
while (rowOffset < rowsPerPage) {
const posY = originY (rowOffset * rowH);
doc.text(cards[cardIdx], posX, posY);
cardIdx = 1;
rowOffset = 1;
}
colOffset = 1;
}
// This is hacky, but PDFKit adds a page by default so the loop doesn't 100% control when a page is added;
// this prevents an empty trailing page from being added
if (cardIdx < cards.length) {
doc.addPage();
}
}
// Finalize PDF file
doc.pipe(fs.createWriteStream('output.pdf'));
doc.end();
當我運行它時,我得到一個包含 4 頁的 PDF,如下所示:

改變colW = 250和colsPerPage = 3:

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/487346.html
