Text inversion in right-to-left languages such as Persian in the Itextsharp Paragraph

رضا جافری 1,296 Reputation points
2021-11-12T23:34:53.513+00:00

First and foremost, I apologize for my grammatical errors; my first language is Persian (Iran).
I want to add Persian text to the PDF headline, but when I do this through the iTextSharp.text.Paragraph class, I get into trouble.
I can solve this problem with the iTextSharp.text.pdf.ColumnText class but I can't exactly put the text alignment in the center.
((PageSize.Left + PageSize.Right)/2)-((TextRenderer.MeasureText("تاریخ گزارش", font).Width)/2), but it's not exactly in the center.

These are my codes:

    public string LatinDigitToPersianDigit(string Text)  
    {  
        string[] Latin = new string[10] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };  
        string[] Persian = new string[10] { "۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹" };  
        for (byte i = 0; i <= 9; i++)  
        {  
            Text = Text.Replace(Latin[i], Persian[i]);  
        }  
        return Text;  
    }  
    void AddPageNumber(string FileIn, string FileOut)  
    {  
        byte[] Bytes = File.ReadAllBytes(FileIn);  
        BaseFont BaseFont = BaseFont.CreateFont(System.Windows.Forms.Application.StartupPath + @"\Font Collection\Bahij Uthman Taha.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);  
        Font PageNumberFont = new Font(BaseFont, 12);  
        using (MemoryStream Stream = new MemoryStream())  
        {  
            PdfReader PDF_Reader = new PdfReader(Bytes);  
            iTextSharp.text.Rectangle PageSize = PDF_Reader.GetPageSize(1);  
            using (PdfStamper Stamper = new PdfStamper(PDF_Reader, Stream))  
            {  
                for (int i = 1; i <= PDF_Reader.NumberOfPages; i++)  
                {  
                  iTextSharp.text.pdf.ColumnText.ShowTextAligned(Stamper.GetUnderContent(i), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit(i.ToString()), PageNumberFont), (PageSize.Left + PageSize.Right) / 2, 15f, 0);  
                }  
            }  
            Bytes = Stream.ToArray();  
        }  
        File.WriteAllBytes(FileOut, Bytes);  
    }  
    public void ExportToPdf(DataGrid dataGrid, DataTable DT, byte VisualColumnIndex)  
    {  
        Document Doc = new Document(PageSize.A4, 10f, 10f, 10f, 10f);  
        PdfWriter PDF_Writer = PdfWriter.GetInstance(Doc, new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\Export.pdf", FileMode.Create));  
        Doc.Open();  
        PDF_Writer.RunDirection = PdfWriter.RUN_DIRECTION_RTL;  
        BaseFont BaseFont = BaseFont.CreateFont(System.Windows.Forms.Application.StartupPath + @"\Font Collection\Bahij Uthman Taha.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);  
        Font DT_Font = new Font(BaseFont, 9);  
        PdfPTable PDF_Table = new PdfPTable(DT.Columns.Count);  
        PDF_Table.WidthPercentage = 100;  
        PDF_Table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;  
        foreach (DataGridColumn Column in dataGrid.Columns)  
        {  
            PDF_Table.AddCell(new Phrase(Column.Header.ToString(), DT_Font));  
        }  
        byte[] ImageByte = null;  
        iTextSharp.text.Image CellImage = null;  
        foreach (DataRow r in DT.Rows)  
        {  
            for (int i = 0; i < DT.Columns.Count; i++)  
            {  
                if (i == VisualColumnIndex)  
                {  
                    ImageByte = (byte[])r[i];  
                    CellImage = iTextSharp.text.Image.GetInstance(ImageByte);  
                    PDF_Table.AddCell(CellImage);  
                }  
                else  
                {  
                    PDF_Table.AddCell(new Phrase(LatinDigitToPersianDigit(r[i].ToString()), DT_Font));  
                }  
            }  
        }  
        string T = '\u202C' + "سلام";  
        iTextSharp.text.Paragraph PG = new iTextSharp.text.Paragraph(T,DT_Font);  
        PG.Alignment = Element.ALIGN_CENTER;  
        PG.SpacingAfter = 20;  
        Doc.Add(PG);  
        Doc.Add(PDF_Table);  
        Doc.Close();  
        AddPageNumber(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\Export.pdf", Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\Export.pdf");  
    }  

Output:

148989-text-inversion.png

149033-page-number.png

Thanks

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,898 questions
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,783 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,995 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
814 questions
{count} votes

1 answer

Sort by: Most helpful
  1. رضا جافری 1,296 Reputation points
    2021-12-20T17:17:35.277+00:00

    I found the solution.
    The iTextSharp.text.Paragraph class does not support right-to-left languages such as Persian (or maybe I could not do it).
    I used the iTextSharp.text.pdf.ColumnText class, to solve this problem and to get the text alignment right in the center we don't need to calculate the length of the text.

    To solve the alignment problem, I used the iTextSharp.text.pdf.ColumnText class, and there is no need to calculate the length of the text to correct the alignment of the text in the center (I mean, this formula: ((PageSize.Left + PageSize.Right)/2)-((TextRenderer.MeasureText("Persian text", font).Width)/2)).
    To put the text exactly above and center only this formula is needed: ((PageSize.Left + PageSize.Right) / 2).

    And to solve the order of Persian letters, I used the arguments of showTextAligned method (these arguments: PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG) like the following code`:

    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase("فهرست کتاب ها", PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
    

    So all the codes are as follows:

        string LatinDigitToPersianDigit(string Text)  
        {  
            string[] Latin = new string[10] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };  
            //I used the Windows Character Map to copy the Persian number.  
            string[] Persian = new string[10] { "۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹" };  
            for (byte i = 0; i <= 9; i++)  
            {  
                Text = Text.Replace(Latin[i], Persian[i]);  
            }  
            return Text;  
        }  
    
        void AddTitleAndPageNumberRTL(string FileIn, string FileOut, [Optional] string Date)  
        {  
            byte[] Bytes = File.ReadAllBytes(FileIn);  
            BaseFont BaseFont = BaseFont.CreateFont(System.Windows.Forms.Application.StartupPath + @"\Font Collection\Bahij Uthman Taha.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);  
            Font PageNumberFont = new Font(BaseFont, 12);  
            PersianCalendar PersianCalendar = new PersianCalendar();  
            using (MemoryStream Stream = new MemoryStream())  
            {  
                PdfReader PDF_Reader = new PdfReader(Bytes);  
                iTextSharp.text.Rectangle PageSize = PDF_Reader.GetPageSize(1);  
                using (PdfStamper Stamper = new PdfStamper(PDF_Reader, Stream))  
                {  
                    PageNumberFont.Size = 14;  
                    switch (Title_TextBox.Foreground != Brushes.Silver && Title_TextBox.Text.Trim() != null)  
                    {  
                        case true:  
                            ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit(Title_TextBox.Text.Trim()), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                            break;  
                        default:  
                            switch (ReportingWindow.RadioButtonStatus)  
                            {  
                                case ReportingWindow.RadioButton.Inventory:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست کتاب ها براساس دارایی از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.DateTaken:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست کتاب ها براساس تاریخ وام از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.ReturnDate:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست کتاب ها براساس تاریخ برگشت از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.ReleaseDate:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست کتاب ها براساس تاریخ چاپ از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.DateOfBirth:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس تاریخ تولد از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.LoanDate:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس تاریخ امانت از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.NumberOfBooksBorrowed:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس تعداد کتاب امانتی از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.BookReturnDate:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس تاریخ برگشت از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.MembershipDate:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس تاریخ عضویت از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.Credit:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس بستانکاری از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                case ReportingWindow.RadioButton.Debt:  
                                    ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit("فهرست اعضا براساس بدهی از " + ReportingWindow.FromValues + " تا " + ReportingWindow.ToValues), PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                    break;  
                                default:  
                                    switch (MainWindow.FlagBook)  
                                    {  
                                        case true:  
                                            ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase("فهرست کتاب ها", PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                            break;  
                                        default:  
                                            ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_CENTER, new Phrase("فهرست اعضا", PageNumberFont), ((PageSize.Left + PageSize.Right) / 2), PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                                            break;  
                                    }  
                                    break;  
                            }  
                            break;  
                    }  
                    switch(Date_TextBox.Visibility)  
                    {  
                        case Visibility.Visible:  
                            ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_RIGHT, new Phrase("تاریخ: " + LatinDigitToPersianDigit(Date.Split('/')[2] + '/' + Date.Split('/')[1] + '/' + Date.Split('/')[0]), PageNumberFont), PageSize.Right - 10, PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                            break;  
                        default:  
                            ColumnText.ShowTextAligned(Stamper.GetUnderContent(1), Element.ALIGN_RIGHT, new Phrase("تاریخ: " + LatinDigitToPersianDigit(PersianCalendar.GetDayOfMonth(DateTime.Now).ToString("00") + "/" + PersianCalendar.GetMonth(DateTime.Now).ToString("00") + "/" + PersianCalendar.GetYear(DateTime.Now).ToString("0000") + " - " + PersianCalendar.GetHour(DateTime.Now).ToString("00") + ":" + PersianCalendar.GetMinute(DateTime.Now).ToString("00")), PageNumberFont), PageSize.Right - 10, PageSize.Top - 10, 0, PdfWriter.RUN_DIRECTION_RTL, ColumnText.AR_LIG);  
                            break;  
                    }  
                    PageNumberFont.Size = 12;  
                    for (int i = 1; i <= PDF_Reader.NumberOfPages; i++)  
                    {  
                        ColumnText.ShowTextAligned(Stamper.GetUnderContent(i), Element.ALIGN_CENTER, new Phrase(LatinDigitToPersianDigit(i.ToString()), PageNumberFont), (PageSize.Left + PageSize.Right) / 2, 7f, 0);  
                    }  
                }  
                Bytes = Stream.ToArray();  
            }  
            File.WriteAllBytes(FileOut, Bytes);  
        }  
    
        public void ExportRTL(DataGrid dataGrid, DataTable DT, byte VisualColumnIndex)  
        {  
            try  
            {  
                Document Doc = new Document(PageSize.A4, 10f, 10f, 27f, 14f);  
                PdfWriter PDF_Writer = PdfWriter.GetInstance(Doc, new FileStream((Path + @"\گزارش.pdf"), FileMode.Create));  
                Doc.Open();  
                PDF_Writer.RunDirection = PdfWriter.RUN_DIRECTION_RTL;  
                BaseFont Base_Font = BaseFont.CreateFont(System.Windows.Forms.Application.StartupPath + @"\Font Collection\Bahij Uthman Taha.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);  
                Font DT_Font = new Font(Base_Font, 10);  
                PdfPTable PDF_Table = new PdfPTable(DT.Columns.Count);  
                PDF_Table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;  
                PDF_Table.WidthPercentage = 100;  
                PdfPCell Cell = new PdfPCell();  
                for (byte i = 0; i < dataGrid.Columns.Count; i++)  
                {  
                    Cell.Colspan = dataGrid.Columns[i].Header.ToString().Count();  
                    PDF_Table.AddCell(new Phrase(dataGrid.Columns[i].Header.ToString(), DT_Font));  
                }  
                byte[] ImageByte = null;  
                iTextSharp.text.Image CellImage = null;  
                DT_Font.Size = 9;  
                for (int i = 0; i < DT.Rows.Count; i++)  
                {  
                    for (byte j = 0; j < dataGrid.Columns.Count; j++)  
                    {  
                        switch (VisualColumnIndex == j)  
                        {  
                            case true:  
                                ImageByte = ((byte[])DT.Rows[i][j]);  
                                CellImage = iTextSharp.text.Image.GetInstance(ImageByte);  
                                PDF_Table.AddCell(CellImage);  
                                break;  
                            default:  
                                PDF_Table.AddCell(new Phrase(LatinDigitToPersianDigit(DT.Rows[i][j].ToString()), DT_Font));  
                                break;  
                        }  
                    }  
                }  
                Doc.Add(PDF_Table);  
                Doc.Close();  
                AddTitleAndPageNumberRTL(Path + @"\گزارش.pdf", Path + @"\گزارش.pdf", Date_TextBox.Text.Trim());  
            }  
            catch(UnauthorizedAccessException)  
            {  
                MessageWindow MW = new MessageWindow();  
                MW.YesButton.Visibility = Visibility.Hidden;  
                MW.NoButton.Visibility = Visibility.Hidden;  
                MW.Image.Source = bmp[3];  
                MW.OKButton.Content = "تایید";  
                MW.LabelTextBlock.FontSize = 17;  
                MW.LabelTextBlock.Text = "دسترسی به مسیر ممنوع است ، خواهشمندیم مسیر دیگری برای ذخیره انتخاب کنید";  
                MW.ShowDialog();  
            }  
            catch(IOException)  
            {  
                MessageWindow MW = new MessageWindow();  
                MW.YesButton.Visibility = Visibility.Hidden;  
                MW.NoButton.Visibility = Visibility.Hidden;  
                MW.Image.Source = bmp[3];  
                MW.OKButton.Content = "تایید";  
                MW.LabelTextBlock.FontSize = 17;  
                MW.LabelTextBlock.Text = "پرونده در فرایندی دیگر باز است ، خواهشمندیم آن را ببندید و دوباره تلاش کنید";  
                MW.ShowDialog();  
            }  
        }  
    

    Results:
    RTL:
    159044-rtl.gif
    LTR:
    159005-ltr.gif

    Thanks

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.