144 lines
4.5 KiB
JavaScript
144 lines
4.5 KiB
JavaScript
const fastify = require('fastify')({
|
|
logger: true,
|
|
bodyLimit: 100 * 1024 * 1024 // 設置為 100MB
|
|
});
|
|
const { PDFDocument, PDFName, StandardFonts, PDFString, PDFPermissionFlag } = require('pdf-lib');
|
|
const cors = require('@fastify/cors');
|
|
|
|
// 更詳細的 CORS 設置
|
|
fastify.register(cors, {
|
|
origin: ['*', 'null'],
|
|
methods: ['GET', 'POST', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type']
|
|
});
|
|
|
|
// 處理 PDF 生成請求
|
|
fastify.post('/generate-pdf', {
|
|
bodyLimit: 100 * 1024 * 1024, // 100MB
|
|
}, async (request, reply) => {
|
|
try {
|
|
const { frames, settings } = request.body;
|
|
|
|
// 檢查 frames 是否為有效數組
|
|
if (!Array.isArray(frames) || frames.length === 0) {
|
|
throw new Error('No frames provided or frames is not an array');
|
|
}
|
|
|
|
// 創建 PDF 文件
|
|
const pdfDoc = await PDFDocument.create();
|
|
|
|
// 設置 PDF 元數據
|
|
if (settings.title) pdfDoc.setTitle(settings.title);
|
|
if (settings.author) pdfDoc.setAuthor(settings.author);
|
|
if (settings.subject) pdfDoc.setSubject(settings.subject);
|
|
if (settings.keywords) pdfDoc.setKeywords(Array.isArray(settings.keywords) ? settings.keywords : []);
|
|
if (settings.creator) pdfDoc.setCreator(settings.creator);
|
|
if (settings.producer) pdfDoc.setProducer(settings.producer);
|
|
if (settings.language) pdfDoc.setLanguage(settings.language);
|
|
|
|
// 設置日期
|
|
pdfDoc.setCreationDate(settings.creationDate ? new Date(settings.creationDate) : new Date());
|
|
pdfDoc.setModificationDate(settings.modificationDate ? new Date(settings.modificationDate) : new Date());
|
|
|
|
// 根據品質設定調整圖片品質
|
|
const qualitySettings = {
|
|
low: { scale: 1 },
|
|
medium: { scale: 2 },
|
|
high: { scale: 3 }
|
|
};
|
|
const quality = qualitySettings[settings.quality || 'medium'];
|
|
|
|
// 處理每個 Frame
|
|
for (const frame of frames) {
|
|
if (!frame.imageBase64) {
|
|
fastify.log.warn(`No image data for frame: ${frame.name}`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
// 解碼 base64 圖片數據
|
|
const imageBuffer = Buffer.from(frame.imageBase64, 'base64');
|
|
|
|
// 嵌入圖片到 PDF
|
|
const image = await pdfDoc.embedPng(imageBuffer);
|
|
|
|
// 獲取圖片尺寸
|
|
const { width, height } = image.scale(1);
|
|
|
|
// 添加新頁面
|
|
const page = pdfDoc.addPage([width, height]);
|
|
|
|
// 繪製圖片
|
|
page.drawImage(image, {
|
|
x: 0,
|
|
y: 0,
|
|
width,
|
|
height,
|
|
});
|
|
|
|
} catch (error) {
|
|
fastify.log.error(`Error processing frame ${frame.name}: ${error.message}`);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// 檢查是否有頁面被添加
|
|
if (pdfDoc.getPageCount() === 0) {
|
|
throw new Error('No valid frames were processed');
|
|
}
|
|
|
|
// 處理加密設置
|
|
if (settings.encryption?.enabled) {
|
|
// 定義權限映射
|
|
const permissionsMap = {
|
|
printing: PDFPermissionFlag.Print,
|
|
modifying: PDFPermissionFlag.ModifyDocument,
|
|
copying: PDFPermissionFlag.Extract,
|
|
annotating: PDFPermissionFlag.Modify,
|
|
};
|
|
|
|
// 收集啟用的權限
|
|
const permissions = [];
|
|
if (settings.encryption.permissions?.printing) permissions.push(permissionsMap.printing);
|
|
if (settings.encryption.permissions?.modifying) permissions.push(permissionsMap.modifying);
|
|
if (settings.encryption.permissions?.copying) permissions.push(permissionsMap.copying);
|
|
if (settings.encryption.permissions?.annotating) permissions.push(permissionsMap.annotating);
|
|
|
|
// 應用加密設置
|
|
await pdfDoc.encrypt({
|
|
userPassword: settings.encryption.userPassword || undefined,
|
|
ownerPassword: settings.encryption.ownerPassword || undefined,
|
|
permissions: permissions
|
|
});
|
|
}
|
|
|
|
// 生成 PDF
|
|
const pdfBytes = await pdfDoc.save();
|
|
|
|
// 設置響應頭
|
|
reply.header('Content-Type', 'application/pdf');
|
|
reply.header('Content-Disposition', `attachment; filename=${settings.filename || 'figma-export.pdf'}`);
|
|
|
|
return reply.send(Buffer.from(pdfBytes));
|
|
|
|
} catch (error) {
|
|
fastify.log.error(error);
|
|
reply.code(500).send({
|
|
error: 'Failed to generate PDF',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
// 啟動服務器
|
|
const start = async () => {
|
|
try {
|
|
await fastify.listen({ port: 3000, host: '0.0.0.0' });
|
|
console.log('Server running at http://localhost:3000');
|
|
} catch (err) {
|
|
fastify.log.error(err);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
start();
|