إنشاء تقارير PDF باستخدام TypeScript مع مكتبة PDF-Lib
\n\nفي تطوير الويب الحديث، غالبًا ما تنشأ الحاجة إلى إنشاء مستندات PDF معقدة: التقارير، الفواتير، الشهادات أو لوحات التحليل. بفضل الكتابة الصارمة، تجعل TypeScript هذه العملية موثوقة وقابلة للتنبؤ. من بين العديد من المكتبات للعمل مع PDF على منصة Node.js وفي المتصفح، تبرز PDF-Lib - أداة خفيفة الوزن وقوية ومكتوبة بالكامل بلغة TypeScript.
\n\nلا تتطلب PDF-Lib تثبيت تبعيات أصلية إضافية (على عكس الحلول الثقيلة مثل Puppeteer أو wkhtmltopdf)، وتعمل في كل من Node.js والمتصفح، وتدعم جميع ميزات PDF الحديثة: تضمين الخطوط والصور، إنشاء النماذج، التعليقات التوضيحية وغيرها الكثير.
\n\nالتثبيت وإنشاء أول مستند
\n\nللبدء، يكفي تثبيت الحزمة عبر npm:
\n\nnpm install pdf-lib\n\nلنقم بإنشاء مستند PDF بسيط مع نص:
\n\nimport { PDFDocument, StandardFonts, rgb } from 'pdf-lib';\n\nasync function createSimplePdf() {\n // إنشاء مستند PDF جديد\n const pdfDoc = await PDFDocument.create();\n\n // إضافة صفحة (حجم A4)\n const page = pdfDoc.addPage([595.28, 841.89]); // A4 بالنقاط\n\n // تضمين خط قياسي\n const font = await pdfDoc.embedFont(StandardFonts.Helvetica);\n\n // رسم النص\n page.drawText('مرحباً بالعالم!', {\n x: 50,\n y: 700,\n size: 30,\n font: font,\n color: rgb(0.2, 0.4, 0.8),\n });\n\n // حفظ المستند كبايتات\n const pdfBytes = await pdfDoc.save();\n return pdfBytes;\n}\n\n// مثال على الاستخدام\ncreateSimplePdf().then((bytes) => {\n // في Node.js يمكن الكتابة إلى ملف\n // require('fs').writeFileSync('hello.pdf', bytes);\n console.log('تم إنشاء PDF! الحجم:', bytes.length, 'بايت');\n});\n\nالعمل مع النص العربي والخطوط المخصصة
\n\nإحدى المهام الرئيسية عند إنشاء التقارير باللغة العربية هي العرض الصحيح للأحرف العربية. الخطوط القياسية لـ PDF (Helvetica, Times, Courier) لا تحتوي على رسوم عربية. الحل هو تضمين خط TrueType يدعم Unicode.
\n\nimport { PDFDocument, rgb } from 'pdf-lib';\nimport fontkit from '@pdf-lib/fontkit';\nimport fs from 'fs';\n\nasync function createArabicPdf() {\n const pdfDoc = await PDFDocument.create();\n\n // تسجيل fontkit للعمل مع الخطوط المخصصة\n pdfDoc.registerFontkit(fontkit);\n\n // تحميل خط يدعم العربية (مثل Noto Naskh Arabic)\n const fontBytes = fs.readFileSync('NotoNaskhArabic-Regular.ttf');\n const customFont = await pdfDoc.embedFont(fontBytes);\n\n const page = pdfDoc.addPage([595.28, 841.89]);\n\n page.drawText('إنشاء تقرير باستخدام TypeScript', {\n x: 50,\n y: 750,\n size: 24,\n font: customFont,\n color: rgb(0, 0, 0),\n });\n\n page.drawText('التاريخ: 2024-01-15', {\n x: 50,\n y: 700,\n size: 14,\n font: customFont,\n color: rgb(0.3, 0.3, 0.3),\n });\n\n return await pdfDoc.save();\n}\n\nإنشاء الجداول والتقارير المنظمة
\n\nلا تحتوي PDF-Lib على وحدة مدمجة للجداول، ولكن يمكن تنفيذها يدويًا بسهولة عن طريق رسم الخطوط وتحديد موضع النص. للراحة، يمكن إنشاء دالة مساعدة:
\n\ninterface TableCell {\n text: string;\n width: number;\n height?: number;\n align?: 'left' | 'center' | 'right';\n}\n\nasync function drawTable(\n page: PDFPage,\n headers: TableCell[],\n rows: TableCell[][],\n startX: number,\n startY: number,\n font: PDFFont,\n fontSize: number = 12\n) {\n const cellPadding = 5;\n const rowHeight = fontSize + 2 * cellPadding;\n let currentY = startY;\n\n // رسم العناوين\n let currentX = startX;\n for (const header of headers) {\n page.drawRectangle({\n x: currentX,\n y: currentY - rowHeight,\n width: header.width,\n height: rowHeight,\n color: rgb(0.9, 0.9, 0.9),\n