- آشنایی با تنظیم قلم به همراه المانهایی که RTL را پشتیبانی میکنند
- روش صحیح تعریف قلم در iTextSharp
- iTextSharp و استفاده از قلمهای محدود فارسی
- iTextSharp و نمایش صحیح تاریخ در متنی راست به چپ
- روش قدیمی تبدیل HTML به PDF با استفاده از کتابخانهی iTextSharp
- تبدیل HTML فارسی به PDF با استفاده از افزونهی XMLWorker کتابخانهی iTextSharp
- نحوهی مقدار دهی عناصر فرمهای خاص PDF، با عبارات فارسی
Install-Package iTextSharp
شروع کار با iTextSharp
معمولا برای کار با iText یک سری روال تکراری از قبیل انتخاب نام فایل نهایی، تعریف فونت، سایز کاغذ، حاشیه بندی و ... را باید طی کنید که کدهای آن را در ذیل مشاهده میکنید:
var fileStream = new FileStream("card.pdf", FileMode.Create, FileAccess.Write, FileShare.None); var docFont = GetFont(); var pageSize = PageSize.A6.Rotate(); // سایز کارت را اینجا باید مشخص کرد var doc = new Document(pageSize); doc.SetMargins(18f, 18f, 15f, 2f); var pdfWriter = PdfWriter.GetInstance(doc, fileStream); doc.Open();
برای درج عکس به صورت شفاف در پس زمینه کارت باید از کد زیر استفاده کرد:
// درج لوگوی مسابقات به صورت شفاف در پس زمینه var canvas = pdfWriter.DirectContentUnder; var logoImg = Image.GetInstance(competitionImagePath); logoImg.SetAbsolutePosition(0, 0); logoImg.ScaleAbsolute(pageSize); var graphicsState = new PdfGState { FillOpacity = 0.2F }; canvas.SetGState(graphicsState); canvas.AddImage(logoImg);
چیدمان و طرح بندی بندی عناصر در iTextSharp
برای طراحی کارت یا کلا کار طراحی، باید با نحوهی قرار دادن و طرح بندی عناصر مثل تصاویر و نوشتهها و ابزارهای مورد نیاز برای این کار، آشنا شوید. خوشبختانه در iText برای این کار ابزارهای خوبی وجود دارد.
حتما با تگ Table در HTML آشنایی دارید. در سالهای دور، حتی کل صفحهی وب را به وسیلهی Table ساختار دهی میکردند. در iTextSharp نیز کلاسی به نام PdfPTable در دسترس است که میتوان از آن به عنوان قالبی برای قرار دادن عناصر، در صفحه استفاده کرد. این Table همانند هر جدولی دارای یک سری سطر و ستون است که میتوانیم عناصر مورد نظرمان مثل تصویر و نوشته و... را در آن قرار دهیم.
// جدولی که برای چیدمان عناصر ارم دانشگاه و عنوان و عکس شخص استفاده میشود var topTable = new PdfPTable(3) { WidthPercentage = 100, RunDirection = PdfWriter.RUN_DIRECTION_RTL, ExtendLastRow = false, }; var universityLogoImage = Image.GetInstance(universityLogoPath); universityLogoImage.ScaleAbsolute(70, 100); topTable.AddCell(new PdfPCell(universityLogoImage) { HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); topTable.AddCell(new PdfPCell(new Phrase("کارت مسابقات دانشگاه آزاد اسلامی", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_CENTER, Border = 0, }); var userImage = Image.GetInstance(userModel.ImagePath); userImage.Border = Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER; userImage.BorderWidth = 1f; userImage.BorderColor = new BaseColor(204, 204, 204); // gray color userImage.ScaleAbsolute(70, 100); topTable.AddCell(new PdfPCell(userImage) { HorizontalAlignment = 2, Border = 0 }); int[] topTableColumnsWidth = { 10, 25, 10 }; topTable.SetWidths(topTableColumnsWidth); doc.Add(topTable);
public class UserModel { public string FirstName { get; set; } public string LastName { get; set; } public string StudentNumber { get; set; } public string NationalCode { get; set; } public string UniversityName { get; set; } public string ImagePath { get; set; } }
using System; using System.IO; using iTextSharp.text; using iTextSharp.text.pdf; using Font = iTextSharp.text.Font; using Image = iTextSharp.text.Image; using Rectangle = iTextSharp.text.Rectangle; namespace ITextSharpCardSample { public class CardReport { public static void Generate(UserModel userModel, string competitionImagePath, string universityLogoPath) { var fileStream = new FileStream("card.pdf", FileMode.Create, FileAccess.Write, FileShare.None); var docFont = GetFont(); var pageSize = PageSize.A6.Rotate(); // سایز کارت را اینجا باید مشخص کرد var doc = new Document(pageSize); doc.SetMargins(18f, 18f, 15f, 2f); var pdfWriter = PdfWriter.GetInstance(doc, fileStream); doc.Open(); // درج لوگوی مسابقات به صورت شفاف در پس زمینه var canvas = pdfWriter.DirectContentUnder; var logoImg = Image.GetInstance(competitionImagePath); logoImg.SetAbsolutePosition(0, 0); logoImg.ScaleAbsolute(pageSize); var graphicsState = new PdfGState { FillOpacity = 0.2F }; canvas.SetGState(graphicsState); canvas.AddImage(logoImg); // جدولی که برای چیدمان عناصر ارم دانشگاه و عنوان و عکس شخص استفاده میشود var topTable = new PdfPTable(3) { WidthPercentage = 100, RunDirection = PdfWriter.RUN_DIRECTION_RTL, ExtendLastRow = false, }; var universityLogoImage = Image.GetInstance(universityLogoPath); universityLogoImage.ScaleAbsolute(70, 100); topTable.AddCell(new PdfPCell(universityLogoImage) { HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); topTable.AddCell(new PdfPCell(new Phrase("کارت مسابقات دانشگاه آزاد اسلامی", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_CENTER, Border = 0, }); var userImage = Image.GetInstance(userModel.ImagePath); userImage.Border = Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER; userImage.BorderWidth = 1f; userImage.BorderColor = new BaseColor(204, 204, 204); // gray color userImage.ScaleAbsolute(70, 100); topTable.AddCell(new PdfPCell(userImage) { HorizontalAlignment = 2, Border = 0 }); int[] topTableColumnsWidth = { 10, 25, 10 }; topTable.SetWidths(topTableColumnsWidth); doc.Add(topTable); // جدول مشخصات شرکت کننده مثل نام و نام خانوادگی var infoTable = new PdfPTable(4) { WidthPercentage = 100, RunDirection = PdfWriter.RUN_DIRECTION_RTL, ExtendLastRow = false, SpacingBefore = 15, }; infoTable.AddCell(new PdfPCell(new Phrase("نام:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0, PaddingBottom = 15 }); infoTable.AddCell(new PdfPCell(new Phrase(userModel.FirstName, docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("نام خانوادگی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase(userModel.LastName, docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("شماره\nدانشجویی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0, PaddingBottom = 15 }); infoTable.AddCell(new PdfPCell(new Phrase(userModel.StudentNumber, docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("کد ملی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase(userModel.NationalCode, docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("واحد دانشگاهی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase(userModel.UniversityName, docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); // دو سلول بعدی صرفا جهت تکمیل شدن یک ردیف است تا عملکرد صحیح خود را داشته باشد infoTable.AddCell(new PdfPCell(new Phrase("", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); int[] infoTableColumnsWidth = { 20, 15, 20, 15 }; infoTable.SetWidths(infoTableColumnsWidth); doc.Add(infoTable); doc.Close(); } private static Font GetFont() { const string fontName = "Iranian Sans"; if (FontFactory.IsRegistered(fontName)) return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); var fontPath = "Fonts/irsans.ttf"; // مسیر فونت FontFactory.Register(fontPath); return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); } } }
class Program { static void Main(string[] args) { var userModel = new UserModel { FirstName = "علی", LastName = "احمدی", NationalCode = "1234567890", StudentNumber = "23242342", UniversityName = "آزاد", ImagePath = "Images/avatar.jpg" }; CardReport.Generate(userModel, "Images/competition_logo.jpg", "Images/university_logo.png"); System.Diagnostics.Process.Start("card.pdf"); } }
Chrome و قابلیت DirectWrite
- گاهی کروم فونتها را صحیح نمایش میدهد و گاهی خیر؛
- در قسمتی از صفحه فونتها درست نمایش داده میشوند و در قسمت دیگر خیر؛
- با رفرش کردن صفحه سالم، فونتها دچار مشکل میشوند و گاهی بالعکس؛
- بعضی اوقات کاراکترهای مربعی نمایش داده میشوند و گاهی کاراکترهای نامفهوم و به هم ریخته.
به هر حال امیدوارم راه حل مناسبی برای این مشکل (با در نظر گرفتن اینکه از فونت استاندارد استفاده شود) پیدا شود...!
- اگر برنامهی download manager ایی نصب است که پسوندهای pdf را به صورت خودکار شناسایی و دریافت میکند، کار به نمایش فایل PDF نخواهد رسید. پسوند PDF را از لیست قابل شناسایی آنها حذف کنید.
- اگر Active-X مربوط به Adobe Reader بر روی سیستم کلاینت نصب نباشد، این روش با تمام مرورگرها کار نخواهد کرد؛ چون تمام آنها PDF Reader ندارند (مانند کروم و یا فایرفاکس).
- اگر از کتابخانهی PDF Report استفاده میکنید، متد data.FlushInBrowser(fileName, FlushType.Inline) نکات بحث فوق را دارد.
- روش دیگر اینکار (نمایش فایل PDF در مرورگر) استفاده از Response.Redirect است به آدرس فایل PDF بر روی سرور. اگر مرورگر PDF Reader و یا Active-X مربوطه را داشته باشد و همچنین برنامهی download manager ایی هم مزاحمت ایجاد نکند، فایل PDF در مرورگر نمایش داده خواهد شد (البته در یک صفحهی جدید).
- با استفاده از افزونهی pdf.js هم میتوان فایلهای PDF را رندر کرد (یک مثال و مثالی دیگر).
Bootstrap Merto RTL 2.2.3 منتشر شد
اولین کاری را که باید جهت شروع به کار با بوت استرپ 4 انجام داد، نصب و افزودن آن به صفحهی HTML جاری است. روشهای زیادی برای انجام اینکار وجود دارند:
الف) استفاده از نگارش SASS آن
بوت استرپ 4 در اصل مبتنی بر SASS توسعه یافتهاست و فایلهای آن با فرمت scss. ارائه میشوند. مزیت کار با این روش، امکان سفارشی سازی بوت استرپ 4 و یا مشارکت در پروژهی آن است و بدیهی است پس از آن باید SASS را به CSS کامپایل و مورد استفاده قرار داد.
ب) استفاده از CDN و یا Content delivery network
- مزیت آن بالا رفتن سرعت سایت با کش شدن آن در شبکه و یا شبکههای توزیع محتوا است.
- اما این روش محدودیت و الزام کار آنلاین با فایلهای بوت استرپ را نیز به همراه دارد.
برای کار با CDNهای بوت استرپ، مطابق راهنمای آن، تنها کافی است مدخل فایل css آنرا به head صفحه و مداخل فایلهای js ذیل را پیش از بسته شدن تگ body قرار دهید:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
- jquery-3.3.1.slim : در اینجا slim یک نگارش بسیار کوچک از jQuery میباشد که بوت استرپ 4 بر مبنای آن کار میکند. البته در یک پروژهی واقعی احتمالا نیاز به نگارش کامل آنرا خواهید داشت و یا اگر قصد حذف کردن جیکوئری را دارید، این نگارش، کمحجمترین آن است.
- popper.min.js : برای نمونه Bootstrap dropdown برای کارکرد صحیح آن در نگارش 4، نیاز به این وابستگی جدید را دارد.
ج) استفاده از فایلهای از پیش پردازش شده
فایلهای از پیش آماده شدهی آنرا میتوان مستقیما از سایت بوت استرپ، با کلیک بر روی دکمهی download واقع در منوی راهبری سایت آن، دریافت کرد. مزیت این روش، امکان کار و توسعهی آفلاین صفحات مبتنی بر بوت استرپ است.
مشکل این روش عدم اطلاع رسانی خودکار از ارائهی نگارشهای جدید و نیاز به دریافت دستی مجدد این بسته، به ازای هر نگارش جدید آن میباشد.
د) استفاده از ابزارهای مدیریت بستهها
روشی را که ما در اینجا از آن استفاده خواهیم کرد، دریافت و نصب وابستگیهای مورد نیاز جهت کار با بوت استرپ 4، توسط npm است. به همین جهت یک فایل جدید package.json را با محتوای ذیل ایجاد کنید:
{ "name": "bootstrap.4", "version": "1.0.0", "description": "client side resources of the project", "scripts": {}, "author": "VahidN", "license": "ISC", "dependencies": { "bootstrap": "^4.1.3", "components-font-awesome": "5.0.6", "jquery": "^3.3.1", "popper.js": "^1.14.4" } }
در اینجا font-awesome را نیز مشاهده میکنید؛ از این جهت که بوت استرپ 4 برخلاف نگارش 3 آن، به همراه گلیف آیکنهای پیشفرض آن نیست.
ایجاد قالب ابتدایی شروع به کار با بوت استرپ 4
پس از دریافت وابستگیهای مورد نیاز جهت شروع به کار با بوت استرپ 4 که هم اکنون باید در پوشهی node_modules واقع در ریشهی پوشهی جاری موجود باشند، در ادامه حداقل قالبی را که برای کار با آن نیاز است، مرور میکنیم:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/components-font-awesome/css/fa-solid.min.css"> <link rel="stylesheet" href="/node_modules/components-font-awesome/css/fontawesome.min.css"> <title>Bootstrap</title> </head> <body> <div class="container"> </div> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <script src="/node_modules/popper.js/dist/umd/popper.min.js"></script> <script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script> </body> </html>
- سپس viewport استاندارد، جهت تعیین اینکه این صفحه با ابزارهای موبایل نیز سازگار است، تعریف شدهاست.
- در قسمت head، مدخل فایل bootstrap.min.css تعریف شدهاست. همچنین مداخل مورد نیاز جهت کار با font-awesome را نیز مشاهده میکنید.
- پیش از بسته شدن تگ body، تعاریف jQuery، کتابخانهی popper و سپس bootstrap.min.js قید شدهاند. کتابخانهی popper از مسیر umd آن دریافت شدهاست تا همه جا کار کند.
نکتهی مهم!
در نگارش نهایی برنامهی شما، مسیرهای فایلهای شروع شدهی با /node_modules/ نباید وجود داشته باشند. این فایلها را بهتر است توسط ابزارهای bundling & minification یکی و سپس به صفحه اضافه کنید.
غنی سازی ویرایشگر VSCode برای کار سادهتر با بوت استرپ
VSCode یک ویرایشگر حرفهای چندسکویی است که برای ویندوز، مک و لینوکس تهیه شدهاست. این ویرایشگر را میتوان توسط افزونههای زیر برای کار سادهتر با بوت استرپ غنی کرد:
Bootstrap 4, Font awesome 4, Font Awesome 5 Free & Pro snippets: ساده سازی تشکیل تگهای بوت استرپ
Path Autocomplete: کار وارد کردن مسیر فایلها و تصاویر را ساده میکند.
HTML CSS Support: کار آن غنی سازی intellisense این ویرایشگر جهت کار با ویژگیها و همچنین کلاسهای CSS است.
IntelliSense for CSS class names in HTML: انتخاب کلاسهای CSS بوت استرپ را سادهتر میکند.
Live Server: کار آن راه اندازی یک وب سرور آزمایشی و سپس امکان مشاهدهی آنی تغییرات در برنامه و فایل HTML جاری، در مرورگر میباشد.
برای کار با آن، در حالیکه صفحهی HTML جاری در VSCode باز است، بر روی دکمهی Go Live اضافه شدهی در status bar آن کلیک کنید. پس از آن، یک وب سرور آزمایشی را بر روی پورت 5500 آغاز کرده و صفحهی جاری را در آدرس http://127.0.0.1:5500/index.html در مرورگر پیشفرض سیستم نمایش میدهد. اکنون فایل HTML خود را در VSCode ویرایش کنید. ملاحظه خواهید کرد که بلافاصله این تغییرات در مرورگر قابل مشاهده هستند.
نگارشهای راست به چپ بوت استرپ 4
قرار است بوت استرپ 4 نگارش رسمی راست به چپ نیز داشته باشد. به همین منظور میتوانید در اینجا رای خود را اظهار کنید.
همچنین پروژههای زیر نیز چنین قابلیتی را ارائه میدهند:
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: Bootstrap4_01.zip