فارسى نویسى و iTextSharp
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: پنج دقیقه


شرح یک سری سعی و خطا!
سعی اول:
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpTests
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

var chunk = new Chunk("آزمایش");
pdfDoc.Add(chunk);
}
}
}
}

نتیجه:



بله! هیچی!

مشکل از کجاست؟
در iTextSharp بر اساس نوع فونت انتخابی و encoding مرتبط،‌ نحوه‌ی رندر سازی حروف مشخص می‌شود:



همانطور که ملاحظه می‌کنید، فونت پایه متنی که قرار است اضافه شود، null است.

سعی دوم:
اینبار فونت را تنظیم می‌کنیم:
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpTests
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var tahomaFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);

var chunk = new Chunk("آزمایش",tahomaFont);
pdfDoc.Add(chunk);
}
}
}
}

توضیحات:
متد BaseFont.CreateFont می‌تواند مسیری از فونت مورد نظر را دریافت کند. این حالت خصوصا برای برنامه‌های وب که ممکن است فونت مورد نظر آن‌ها در سرور نصب نشده باشد، بسیار مفید است و لزومی ندارد که الزاما فونت مورد استفاده در پوشه fonts‌ ویندوز نصب شده باشد.
نکات مهم دیگر بکار گرفته شده در این متد، استفاده از BaseFont.IDENTITY_H و BaseFont.EMBEDDED است. به این صورت encoding متن، جهت نوشتن متون غیر Ansi تنظیم می‌شود و در این حالت حتما باید فونت را در فایل، مدفون (embed) نمود. از این لحاظ که عموما این نوع فونت‌ها در سیستم‌های کاربران نصب نیستند.

نتیجه:



بد نیست! حداقل حروف نمایش داده شدند؛ اما نیاز است تا چرخانده یا معکوس شوند. برای انجام خودکار آن حداقل دو کار را می‌توان انجام داد.

الف) استفاده از ColumnText و اعمال تنظیمات راست به چپ آن
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpTests
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var tahomaFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);

ColumnText ct = new ColumnText(pdfWriter.DirectContent);
ct.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
ct.SetSimpleColumn(100, 100, 500, 800, 24, Element.ALIGN_RIGHT);

var chunk = new Chunk("آزمایش", tahomaFont);

ct.AddElement(chunk);
ct.Go();
}
}
}
}

توضیحات:
در اینجا یک ColumnTex جدید تعریف و سپس خصوصیات این ستون تنظیم شده، به همراه RunDirection آن که اصل قضیه است. سپس chunk تعریف شده را به این ستون اضافه کرده‌ایم.

نتیجه:



بله! کار کرد!

ب) استفاده از PdfTable و اعمال تنظیمات راست به چپ آن
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpTests
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();

var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var tahomaFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);

PdfPTable table = new PdfPTable(numColumns: 1);
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
table.ExtendLastRow = true;

PdfPCell pdfCell = new PdfPCell(new Phrase("آزمایش", tahomaFont));
pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;

table.AddCell(pdfCell);
pdfDoc.Add(table);
}
}
}
}

در حین استفاده از PdfTable هم لازم است تا RunDirection مربوط به خود جدول و همچنین هر سلول اضافه شده به آن به RTL تنظیم شوند.

این نکات در هر جایی که با این کتابخانه سر و کار داریم باید اعمال شوند. برای مثال:

افزودن Header به صفحات Pdf :
افزودن header در نگارش‌های جدید iTextSharp شامل نکته استفاده از کلاس PdfPageEventHelper به شرح زیر است (و مثال‌هایی را که در وب پیدا خواهید کرد، هیچکدام با آخرین نگارش موجود iTextSharp کار نمی‌کنند):
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iTextSharpTests
{
public class PageEvents : PdfPageEventHelper
{
Font _font;
public PageEvents()
{
var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
_font = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
}

public override void OnStartPage(PdfWriter writer, Document document)
{
base.OnStartPage(writer, document);

PdfPTable table = new PdfPTable(numColumns: 1);
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;

PdfPCell pdfCell = new PdfPCell(new Phrase("سر صفحه در صفحه: " + writer.PageNumber, _font));
pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
pdfCell.HorizontalAlignment = Element.ALIGN_CENTER;

table.AddCell(pdfCell);
document.Add(table);
}
}

class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfWriter.PageEvent = new PageEvents();
pdfDoc.Open();

var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var tahomaFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);

PdfPTable table = new PdfPTable(numColumns: 1);
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
table.ExtendLastRow = true;

PdfPCell pdfCell = new PdfPCell(new Phrase("آزمایش", tahomaFont));
pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;

table.AddCell(pdfCell);
pdfDoc.Add(table);

pdfDoc.NewPage();
}
}
}
}

نتیجه:



تنها نکته‌ای که اینجا اضافه شده، تعریف کلاس PageEvents است که از کلاس PdfPageEventHelper مشتق شده است. در این کلاس می‌توان یک سری متد کلاس پایه را تحریف کرد و header و footer و غیره را اضافه نمود. سپس جهت اضافه کردن آن، pdfWriter.PageEvent باید مقدار دهی شود.
در اینجا هم اگر نوع فونت، encoding و PdfTable به همراه RunDirection آن اضافه نمی‌شد، یا چیزی در header صفحه قابل مشاهده نبود یا متن مورد نظر معکوس نمایش داده می‌شد.

  • #
    ‫۱۳ سال و ۳ ماه قبل، شنبه ۱۱ تیر ۱۳۹۰، ساعت ۱۸:۲۶
    ممنون از مطلب خوبتون مثل همیشه عالی.
  • #
    ‫۱۳ سال و ۲ ماه قبل، یکشنبه ۹ مرداد ۱۳۹۰، ساعت ۱۹:۴۸
    خدا خیرت بده مشکل جماعتی رو حل کردی
  • #
    ‫۱۳ سال و ۱ ماه قبل، دوشنبه ۲۱ شهریور ۱۳۹۰، ساعت ۱۸:۱۱
    ممنونم، فقط این کار در زمانی که از html استفاده میکنم جواب نمیده.
    یعنی با html هم کار میکنه؟ مشکل کار من کجاست؟ باید کار اضافه ای کنم که نمیکنم؟؟؟
    لطفا راهنمایی بفرمایید
  • #
    ‫۱۳ سال و ۱ ماه قبل، دوشنبه ۲۱ شهریور ۱۳۹۰، ساعت ۲۰:۴۱
    در مورد html to pdf فارسی، یک سری نکات خاص خودش وجود دارد که مفصل توضیح دادم: (+)
  • #
    ‫۱۲ سال و ۳ ماه قبل، پنجشنبه ۱۵ تیر ۱۳۹۱، ساعت ۰۷:۴۰
    ممنون آقا وحید، عالی
  • #
    ‫۱۲ سال و ۱ ماه قبل، یکشنبه ۱۲ شهریور ۱۳۹۱، ساعت ۰۵:۳۹
    با سلام ، من کد زیر رو نوشتم
     var m = new ITModel.ITModelContainer();
            var list = (from pp in m.PERSONNELs
                        select pp).ToList();
    
            string pdfpath = Server.MapPath("PDFs");
            using (var pdfDoc = new Document(PageSize.A4))
            {
                var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream(pdfpath + "/Personnel2.pdf", FileMode.Create));
                pdfDoc.Open();
                var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
                var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                var tahomaFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.BLACK);
                float[] widths = new float[] { 1f, 2f };
    
                PdfPTable table = new PdfPTable(2)
                    {
                        TotalWidth = 216f,
                        LockedWidth = true,
                        HorizontalAlignment = 0,
                        SpacingBefore = 20f,
                        SpacingAfter = 30f
                    };
    
                table.SetWidths(widths);
                PdfPCell cell = new PdfPCell(new Phrase("لیست پرسنل", tahomaFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, Colspan = 2, Border = 0, HorizontalAlignment = 1 };
    
                table.AddCell(cell);
                foreach (var item in list)
                {
                    PdfPCell cell2 = new PdfPCell(new Phrase(item.PERSON_ID.ToString(), tahomaFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
                    PdfPCell cell3 = new PdfPCell(new Phrase(item.FIRST_NAME + " " + item.LAST_NAME, tahomaFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
                    table.AddCell(cell2);
                    table.AddCell(cell3);
                }
                pdfDoc.Add(table);
            }
    آیا امکانش هست که ما به جای اینکه بیایم در هر Cell کد زیر را بنویسیم یک بار برای کد جدول اینو تعریف کنیم؟
    { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
    چون اگه بخواهیم کدهای مربوط به تنظیم فوت رو برای هر Cell بنویسیم یه خورده کدها زیاد میشه.
    ممنون میشم راهنمایی کنید
    مرسی
    • #
      ‫۱۲ سال و ۱ ماه قبل، یکشنبه ۱۲ شهریور ۱۳۹۱، ساعت ۱۳:۲۰
      نه. لازم است به ازای هر سلول اینکار انجام شود.
      ضمنا یک نکته کلی در مورد PDF وجود دارد و آن هم این است که ساختار PDF یک canvas است (یک تابلو نقاشی برداری). یعنی مفاهیمی مانند جدول، سلول، پاراگراف و غیره در پشت صحنه آن وجود خارجی ندارند و فقط کتابخانه‌های تولید PDF است که این نوع امکانات را جهت سهولت کار اختراع کرده‌اند. بنابراین به ازای هر شیءایی که اضافه می‌شود باید اطلاعات دقیق آن نیز درج شود.

  • #
    ‫۱۱ سال و ۳ ماه قبل، شنبه ۱ تیر ۱۳۹۲، ساعت ۱۹:۳۵
    با عرض خسته نباشید
    اگر در داده‌ها ترکیبی از حروف فارسی و انگلیسی باشه با این روش کار نمیکنه.مثلا با فونت B Lotus حروف انگلیسی نمایش داده نمیشه.در بهترین حالت من فونت Tahoma رو استفاده میکنم که بازم اعدادم انگلیسی هست.
    آیا اشکال از فونته؟ نمیتونم دوتا فونت براش بفرستم ؟ 
    یا اینکه باید فونتی بسازم که همه جور حروفی رو داشته باشه؟
  • #
    ‫۱۰ سال و ۱۰ ماه قبل، دوشنبه ۱۱ آذر ۱۳۹۲، ساعت ۱۳:۵۸
    باسلام 
    ممنون از راهنمایی تون  عالی بود
    اما برای راست چین کردن متون باید چیکار کرد؟
    من این دو خط رو اضافه کردم 
    cell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
    cell.RunDirection = PdfWriter.DirectionR2L;
    اما باز هم کار نمیکنه !
    • #
      ‫۱۰ سال و ۱۰ ماه قبل، دوشنبه ۱۱ آذر ۱۳۹۲، ساعت ۱۴:۱۰
      - به تصویر آخر و کدهای آن دقت کنید. کلمه آزمایش از سمت راست شروع شده.
      - DirectionR2L کاربردی ندارد در اینجا. PdfWriter.RUN_DIRECTION_RTL باید باشد.
  • #
    ‫۱۰ سال و ۸ ماه قبل، سه‌شنبه ۱۵ بهمن ۱۳۹۲، ساعت ۲۰:۴۳
    سلام؛ آیا امکانش هست که برای کلمه آزمایش بطور مثال مختصات تعریف کرد تا در اون مختصات توی صفحه نمایش داده بشه؟
    • #
      ‫۱۰ سال و ۸ ماه قبل، سه‌شنبه ۱۵ بهمن ۱۳۹۲، ساعت ۲۳:۴۷
      بله. باید از متد ColumnText.ShowTextAligned استفاده کنید:
      ColumnText.ShowTextAligned(
                              canvas: pdfWriter.DirectContent,
                              alignment: Element.ALIGN_RIGHT,
                              phrase: new Phrase("لیست پرسنل", tahomaFont),
                              x: 40,
                              y: 30,
                              rotation: 0,
                              runDirection: PdfWriter.RUN_DIRECTION_RTL,
                              arabicOptions: 0);