نظرات مطالب
iTextSharp و استفاده از قلم‌های محدود فارسی
یک نکته‌ی تکمیلی
اگر از PDF Report استفاده می‌کنید، نکته‌ی FontSelector فوق، به صورت توکار در آن لحاظ شده‌است. بنابراین اولین قلم را در اینجا یک قلم فارسی تعریف کنید:
            .DefaultFonts(fonts =>
            {
                fonts.Path(System.IO.Path.Combine(AppPath.ApplicationPath, "fonts\\irsans.ttf"),
                           System.IO.Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "fonts\\verdana.ttf"));
                fonts.Size(9);
                fonts.Color(System.Drawing.Color.Black);
            })
و دومین قلم را یک قلم کامل انگلیسی. این دو مورد مکمل هم خواهند شد؛ چون قلم فارسی استفاده شده، گلیف‌های انگلیسی را ندارد.
بازخوردهای پروژه‌ها
مشکل عمل نکردن فونت فارسی
سلام
باتشکر از شما
آقای نصیری بنده برای راحتی استفاده در برنامه یک کلاس استاتیک بصورت زیر تعریف کرده ام :
  public static class ReportMethod
    {
        static FontSelector fontSelector = new FontSelector();
        const char RightToLeftEmbedding = (char)PersianDate.RightToLeftEmbedding;
        const char PopDirectionalFormatting = (char)PersianDate.PopDirectionalFormatting;
        public static Dictionary<string, string> fontDicBody = new Dictionary<string, string> { { "BMitra", "B Mitra" }, { "tahoma", "tahoma" } };
        public static Dictionary<string, string> fontDicHeader1 = new Dictionary<string, string> { { "BMitraBd", "B Mitra Bold" }, { "tahoma", "tahoma" } };
        public static Dictionary<string, string> fontDicHeader2 = new Dictionary<string, string> { { "BTitrBd", "B Titr Bold" }, { "tahoma", "tahoma" } };
        public static Dictionary<string, string> fontDicFooter = new Dictionary<string, string> { { "BMitra", "B Mitra" }, { "tahoma", "tahoma" } };

        public static string FixWeakCharacters(string data)
        {
            if (string.IsNullOrWhiteSpace(data))
                return string.Empty;
            var weakCharacters = new[] { @"\", "/", "+", "-", "=", ";", "$" };
            foreach (var weakCharacter in weakCharacters)
            {
                data = data.Replace(weakCharacter, RightToLeftEmbedding + weakCharacter + PopDirectionalFormatting);
            }
            return data;
        }

        public static Phrase SetFont(string data, int fontType)
        {
            Dictionary<string, string> fontDic;
            float fontSize = 11;
            switch (fontType)
            {
                case 0:
                    fontDic = fontDicBody;
                    fontSize = 11;
                    break;
                case 1:
                    fontDic = fontDicHeader1;
                    fontSize = 14;
                    break;
                case 2:
                    fontDic = fontDicFooter;
                    fontSize = 12;
                    break;
                case 11:
                    fontDic = fontDicHeader2;
                    fontSize = 18;
                    break;
                default:
                    fontDic = fontDicBody;
                    fontSize = 11;
                    break;
            }
            foreach (var item in fontDic)
            {
                FontFactory.Register("c:\\windows\\fonts\\" + item.Key + ".ttf");
                Font newfont = FontFactory.GetFont(item.Value, BaseFont.IDENTITY_H, fontSize);
                if (newfont.Familyname != "unknown")
                    fontSelector.AddFont(newfont);
            }
            return fontSelector.Process(FixWeakCharacters(data));
        }

        public static PdfPCell SetCell(string text, int border, int colspan, int Horizontal, int Vertical, bool DirectionRTL, int fontType = 0)
        {
            if (DirectionRTL)
            {
                var cell = new PdfPCell { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
                cell.Border = border;
                cell.Colspan = colspan;
                cell.HorizontalAlignment = Horizontal;
                cell.VerticalAlignment = Vertical;
                cell.Phrase = new Phrase(ReportMethod.SetFont(text, fontType));
                return cell;
            }
            else
            {
                var cell = new PdfPCell();
                cell.Border = border;
                cell.Colspan = colspan;
                cell.HorizontalAlignment = Horizontal;
                cell.VerticalAlignment = Vertical;
                cell.Phrase = new Phrase(ReportMethod.SetFont(text, fontType));
                return cell;
            }
        }
    }
که این کلاس برای ایجاد سلول با فونت مورد نظر من معرفی شده است
و کد گزارش من به صورت زیر تعریف شده است :
    public IPdfReportData CreatePdfReport_SRptTeach(int MemberID, List<sp_Teach_Communicate_Select_ReportTeachResult> Teach_Result, string st, List<sp_Institute_Center_Info_Select_Name_MasterResult> Info)
        {
            string fileName = string.Format("SRptTeach-{0}.pdf", Guid.NewGuid().ToString("N"));            
            return new PdfReport()
                                  .DocumentPreferences(doc =>
                                  {
                                      doc.RunDirection(PdfRunDirection.RightToLeft);
                                      doc.Orientation(PageOrientation.Landscape);
                                      doc.PageSize(PdfPageSize.A4);
                                      doc.DocumentMetadata(new DocumentMetadata { Author = Info[0].InstName, Application = "PdfRpt", Keywords = "گزارش", Subject = "گزارش ویژه", Title = "گزارش کارکرد مدرسید" });
                                      doc.Compression(new CompressionSettings
                                      {
                                          EnableCompression = true,
                                          EnableFullCompression = true
                                      });
                                      doc.PrintingPreferences(new PrintingPreferences
                                      {
                                          ShowPrintDialogAutomatically = false
                                      });
                                  })
                                  .DefaultFonts(fonts =>
                                  {
                                      fonts.Path(System.IO.Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "fonts\\" + ReportMethod.fontDicBody.ElementAt(0).Key + ".ttf"),
                                          System.IO.Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "fonts\\" + ReportMethod.fontDicBody.ElementAt(1).Key + ".ttf"));
                                      fonts.Size(11);
                                      fonts.Color(System.Drawing.Color.Black);
                                  })
                                  .PagesFooter(footer =>
                                  {
                                      footer.CustomFooter(new CustomFooter(footer.PdfFont, PdfRunDirection.RightToLeft));
                                  })
                                  .PagesHeader(header =>
                                  {
                                      header.CustomHeader(new CustomHeader_SRptTeach(MemberID, st, Info));
                                  })
                                  .MainTableTemplate(template =>
                                  {
                                      //template.BasicTemplate(BasicTemplate.SimpleTemplate);
                                      template.CustomTemplate(new TransparentTemplate());
                                  })
                                  .MainTablePreferences(table =>
                                  {
                                      table.ColumnsWidthsType(TableColumnWidthType.Relative);
                                      table.GroupsPreferences(new GroupsPreferences
                                      {
                                          GroupType = GroupType.IncludeGroupingColumns,
                                          RepeatHeaderRowPerGroup = true,
                                          ShowOneGroupPerPage = false,
                                          SpacingBeforeAllGroupsSummary = 5f,
                                          ShowGroupingPropertiesInAllRows = true
                                      });
                                  })
                                  .MainTableDataSource(dataSource =>
                                  {
                                      dataSource.StronglyTypedList<sp_Teach_Communicate_Select_ReportTeachResult>(Teach_Result);
                                  })
                                  .MainTableSummarySettings(summarySettings =>
                                  {
                                      summarySettings.OverallSummarySettings("جمع مبالغ");
                                      summarySettings.AllGroupsSummarySettings("جمع کل مبالغ");
                                  })
                                  .MainTableColumns(columns =>
                                  {
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.RowNo);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(0);
                                          column.Width(4);
                                          column.HeaderCell("ردیف");
                                      });

                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.ParentName);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(1);
                                          column.Width(5);
                                          column.HeaderCell("مرکز");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.FullName);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(2);
                                          column.Width(12);
                                          column.HeaderCell("نام و نام خانوادگی");
                                          column.Group(true,
                                              (val1, val2) =>
                                              {
                                                  return val1.ToString() == val2.ToString();
                                              });
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TermInfoName);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(3);
                                          column.Width(8);
                                          column.HeaderCell("ترم");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Contract_NO);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(4);
                                          column.Width(7);
                                          column.HeaderCell("شماره قرارداد");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.LessonFullCode);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(5);
                                          column.Width(4);
                                          column.HeaderCell("کد درس");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.LessonName);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(6);
                                          column.Width(10);
                                          column.HeaderCell("نام درس");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Start_Date_Lesson);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(7);
                                          column.Width(6);
                                          column.HeaderCell("تاریخ شروع");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.End_Date_Lesson);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(8);
                                          column.Width(6);
                                          column.HeaderCell("تاریخ پایان");
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TeachAmount);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(9);
                                          column.Width(6);
                                          column.HeaderCell("مبلغ حق التدریس(ریال)");
                                          column.ColumnItemsTemplate(template =>
                                          {
                                              template.TextBlock();
                                              template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                                          });
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.DoTeacherTime);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(10);
                                          column.Width(3);
                                          column.HeaderCell("ساعت کارکرد");
                                          column.ColumnItemsTemplate(template =>
                                          {
                                              template.TextBlock();
                                              template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                                          });
                                          column.AggregateFunction(aggregateFunction =>
                                          {
                                              aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                                              aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                                          });
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName("CanPay");
                                          column.CalculatedField(true,
                                              list =>
                                              {
                                                  if (list == null)
                                                      return string.Empty;
                                                  var amount = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.TeachAmount);
                                                  var doTime = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.DoTeacherTime);
                                                  var result = float.Parse(amount) * float.Parse(doTime);
                                                  return Convert.ToDecimal(result);
                                              });
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(11);
                                          column.Width(7);
                                          column.HeaderCell("قابل پرداخت(ریال)");
                                          column.ColumnItemsTemplate(template =>
                                          {
                                              template.TextBlock();
                                              template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                                          });
                                          column.AggregateFunction(aggregateFunction =>
                                          {
                                              aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                                              aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                                          });
                                      });
                                      columns.AddColumn(column =>
                                      {
                                          column.PropertyName<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Personal_Education);
                                          column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                          column.IsVisible(true);
                                          column.Order(12);
                                          column.Width(6);
                                          column.HeaderCell("مدرک تحصیلی");
                                      });
                                      //columns.AddColumn(column =>
                                      //{
                                      //    column.PropertyName("Descriptions");
                                      //    column.CalculatedField(true,
                                      //        list =>
                                      //        {
                                      //            if (list == null)
                                      //                return string.Empty;
                                      //            var Row = list.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.RowNoPerson);
                                      //            return "";
                                      //        });
                                      //    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                                      //    column.IsVisible(true);
                                      //    column.Order(13);
                                      //    column.Width(3);
                                      //    column.HeaderCell("توضیحات");
                                      //});
                                  })
                                  .MainTableEvents(events =>
                                  {
                                      events.DataSourceIsEmpty(message: "اطلاعاتی برای نمایش وجود ندارد.");
                                      events.DocumentClosing(docClose =>
                                      {
                                          string[] msgField = { "مدیر گروه", Info.Where(sp => sp.ID == MemberID).FirstOrDefault().InstKindName, Info.Where(sp => sp.ID == 0).FirstOrDefault().InstKindName, "امور مالی", "معاون پشتیبانی" };
                                          string[] dataField = { "", Info.Where(sp => sp.ID == MemberID).FirstOrDefault().MasterName, Info.Where(sp => sp.ID == 0).FirstOrDefault().MasterName, "", Info.Where(sp => sp.ID == 1).FirstOrDefault().MasterName };
                                          var infoTable = new PdfGrid(msgField.Length) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, WidthPercentage = 100 };
                                          foreach (var item in msgField)
                                          {
                                              infoTable.AddCell(ReportMethod.SetCell(item, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true));
                                          }
                                          foreach (var item in dataField)
                                          {
                                              infoTable.AddCell(ReportMethod.SetCell(item, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true));
                                          }
                                          docClose.PdfDoc.Add(infoTable);
                                      });
                                  })
                                  .Export(export =>
                                  {
                                      export.ToExcel();
                                      export.ToCsv();
                                      export.ToXml();
                                      export.ToString();
                                  })
                                  .Generate(data =>
                                  {
                                      fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8);
                                      data.FlushInBrowser(fileName, FlushType.Inline);
                                  });
            //.Generate(data => data.AsPdfFile(string.Format("{0}\\PlansPage\\RptIListSample-{1}.pdf", AppPath.ApplicationPath, Guid.NewGuid().ToString("N"))));
        }
و قسمت هدر گزارش به صورت سفارشی به صورت زیر معرفی شده است :
namespace Academy.Control.Reports
{
    public class CustomHeader_SRptTeach : IPageHeader
    {
        public IPdfFont PdfRptFont { set; get; }
        string st;
        List<sp_Institute_Center_Info_Select_Name_MasterResult> Info;
        int MemberID;

        public CustomHeader_SRptTeach(int MemberID, string st, List<sp_Institute_Center_Info_Select_Name_MasterResult> Info)
        {
            this.st = st;
            this.Info = Info;
            this.MemberID = MemberID;
        }

        public PdfGrid RenderingGroupHeader(Document pdfDoc, PdfWriter pdfWriter, IList<CellData> rowdata, IList<SummaryCellData> summaryData)
        {
            // return null;
            var groupFullName = rowdata.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.FullName);
            var groupPersonalEducation = rowdata.GetSafeStringValueOf<sp_Teach_Communicate_Select_ReportTeachResult>(x => x.Personal_Education);

            var table = new PdfGrid(2) { WidthPercentage = 100 };
            table.AddSimpleRow(
                (cellData, cellProperties) =>
                {
                    cellData.Value = "نام و نام خانوادگی:";
                    cellProperties.PdfFont = PdfRptFont;
                    cellProperties.PdfFontStyle = DocumentFontStyle.Bold;
                    cellProperties.HorizontalAlignment = HorizontalAlignment.Left;
                },
                (cellData, cellProperties) =>
                {
                    cellData.Value = groupFullName;
                    cellProperties.PdfFont = PdfRptFont;
                    cellProperties.HorizontalAlignment = HorizontalAlignment.Left;
                });
            table.AddSimpleRow(
                (cellData, cellProperties) =>
                {
                    cellData.Value = "مدرک تحصیلی :";
                    cellProperties.PdfFont = PdfRptFont;
                    cellProperties.PdfFontStyle = DocumentFontStyle.Bold;
                    cellProperties.HorizontalAlignment = HorizontalAlignment.Left;
                },
                (cellData, cellProperties) =>
                {
                    cellData.Value = groupPersonalEducation;
                    cellProperties.PdfFont = PdfRptFont;
                    cellProperties.HorizontalAlignment = HorizontalAlignment.Left;
                });
            return table.AddBorderToTable(borderColor: BaseColor.LIGHT_GRAY, spacingBefore: 10f);

        }    

        public PdfGrid RenderingReportHeader(Document pdfDoc, PdfWriter pdfWriter, IList<SummaryCellData> summaryData)
        {
            var tableMain = new PdfGrid(1) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, WidthPercentage = 100 };
            tableMain.DefaultCell.Border = PdfPCell.NO_BORDER;
            PdfGrid table = new PdfGrid(3);
            table.DefaultCell.Border = PdfPCell.NO_BORDER;

            table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false));
            table.AddCell(ReportMethod.SetCell("گزارش کارکرد مدرسین ", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, true,11));
            PdfPTable tbRight = new PdfPTable(1) { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
            tbRight.DefaultCell.Border = PdfPCell.NO_BORDER;

            Image _image = Image.GetInstance(System.IO.Path.Combine(AppPath.ApplicationPath, "Content\\Images\\p_jahad2.jpg"));
            var cellImg = new PdfPCell(_image, false) { Border = PdfPCell.NO_BORDER };
            cellImg.HorizontalAlignment = PdfPCell.ALIGN_CENTER;
            tbRight.AddCell(cellImg);
            tbRight.AddCell(ReportMethod.SetCell(Info[0].InstName, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false,1));
            tbRight.AddCell(ReportMethod.SetCell(Info.Where(sp => sp.ID == MemberID).FirstOrDefault().SecondName, PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false,1));
            table.AddCell(tbRight);

            PdfGrid tbLeft = new PdfGrid(2) { RunDirection = PdfWriter.RUN_DIRECTION_RTL };
            tbLeft.DefaultCell.Border = PdfPCell.NO_BORDER;
            tbLeft.AddCell(ReportMethod.SetCell("تاریخ گزارش : " + System.DateTime.Now.ToPersianDateTime("/", false), PdfPCell.NO_BORDER, 2, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false));
            tbLeft.AddCell(ReportMethod.SetCell("از تاریخ " + st.Split(';')[0], PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false));
            tbLeft.AddCell(ReportMethod.SetCell("تا تاریخ " + st.Split(';')[1], PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_LEFT, PdfPCell.ALIGN_MIDDLE, false));

            table.AddCell(tbLeft);
            table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false));
            table.AddCell(ReportMethod.SetCell("", PdfPCell.NO_BORDER, 1, PdfPCell.ALIGN_CENTER, PdfPCell.ALIGN_MIDDLE, false));
            tableMain.AddCell(table);
            return tableMain;
        }
    }
}
حالا من دو مشکل دارم که هرچی سعی کردم نتونستم این موارد را رفع کنم و درخواست راهنمایی دارم از شما :
1. فونت هایی که من معرفی کردم برای هدر اصلا اعمال نمی‌شود و همینطور فونت در متن اصلی هم که تغییر میدم باز تغییر ایجاد نمیشه و به نظر میاد اصلا اعمال نمیشه به کل و هدر و متن با یک فونت نمایش داده میشه در صورتی که من فونت‌ها و سایز‌های متفاوتی برای متن‌ها انتخاب میکنم و اعمال میکنم
2. قسمت گروه هدری که من معرفی کردم اصلا کار نمیکنه و نمایش داده نمیشه
ممنون میشم شما من رو راهنمایی کنید 
مثال‌های قبلی رو هم دیدم در مورد فونت و گروه هدر و سعی کردم مثل همون موارد اعمال کنم اما باز اعمال نشد
متشکرم از وقتی که می‌گذارید
مطالب
تعیین Fallback font برای قلم‌های فارسی در WPF

اکثر قلم‌های فارسی، فاقد تعاریف مرتبط با حروف انگلیسی هستند. البته عموم کاربران متوجه این امر نمی‌شوند چون ویندوز دو مفهوم Font Fallback و Font Linking را جهت پوشش glyph های تعریف نشده، در پشت صحنه اعمال خواهد کرد. جزئیات بیشتر در اینجا: (^ و ^)

به صورت خلاصه کار Font Fallback در ویندوز جایگزینی خودکار قلم مورد استفاده است؛ تحت شرایط زیر:
- فونت تعریف شده در برنامه، در سیستم کاربر وجود نداشته باشد.
- تعاریف Glyphهای بکارگرفته شده در متن جاری، در قلم انتخابی وجود نداشته باشند.

در WPF این مساله کاملا قابل کنترل است. قلمی که به صورت خودکار به عنوان جایگزین مطرح می‌شود در قلمی به نام "Global User Interface" تعریف شده است. تعاریف این قلم ترکیبی هم در فایلی به نام GlobalUserInterface.CompositeFont در پوشه فونت‌های سیستم موجود است (برای مثال، مسیر c:\windows\fonts حاوی این فایل متنی است).
اگر این فایل XML را با یک ادیتور متنی باز کنید، مشاهده خواهید کرد که بازه‌های مختلف کاراکترهای یونیکد، به فونت‌های پیش فرضی نگاشت شده‌اند. بنابراین اگر این سؤال وجود دارد که در متن مخلوط فارسی و انگلیسی من، فونت پیش فرض حروف انگلیسی از کجا تامین و مشخص می‌شود، پاسخ را در این فایل می‌توانید مشاهده کنید.

روش دیگری هم برای تعیین Fallback font در WPF وجود دارد. یک مثال:

<Window x:Class="WpfFontTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock
Text="نمایش مخلوطی از متن فارسی و متن English با هم"
Margin="7"
FontFamily="Fonts/BNazanin.ttf#B Nazanin, Comic Sans Ms"
FontSize="25"
FlowDirection="RightToLeft"
VerticalAlignment="Top" HorizontalAlignment="Center" />
</Grid>
</Window>

در این مثال فونت B Nazanin در برنامه قرار داده شده است (embedded font). همچنین در کنار آن پس از علامت کاما، Fallback font مشخص است. به این معنا که تاجایی که میسر است لطفا از فونت B Nazanin برای نمایش متن مورد نظر استفاده شود؛ اگر نشد از قلم Comic Sans Ms استفاده گردد. قلم B Nazanin حاوی تعاریف حروف انگلیسی نیست. بنابراین WPF جهت نمایش آن‌ها از فونت دوم معرفی شده کمک می‌گیرد. توضیحات بیشتر در اینجا: (^)

نظرات مطالب
معرفی کتابخانه PdfReport
- لطفا برای پرسش و پاسخ در مورد این پروژه، از قسمت مخصوص آن در سایت استفاده کنید.
- یکسری از قلم‌های فارسی ناقص هستند: «iTextSharp و استفاده از قلم‌های محدود فارسی». یا از قلم خوب استفاده کنید و یا جائیکه دو قلم این گزارشگیر را معرفی می‌کنید، دو قلم مکمل را تعریف و معرفی کنید.
مطالب
فارسی نویسی و 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 به PDF با استفاده از کتابخانه‌ی iTextSharp
- در مورد فارسی نویسی در iTextSharp یک دیباگ مرحله به مرحله قبلا در سایت مطرح شده. اگر خروجی یونیکد نگرفتید یعنی قلم صحیحی در حال استفاده نیست. کدهایی که قبلا ارسال کرده بودم به این نحو است:
// روش صحیح تعریف فونت  
var systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
FontFactory.Register(Path.Combine(systemRoot, "fonts\\tahoma.ttf"));
در کدهای شما به این نحو:
var systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
FontFactory.Register(Path.Combine(systemRoot, "c:\\windows\\fonts\\tahoma.ttf"));
با توجه به استفاده از Path.Combine، مسیری را که معرفی کرده‌اید می‌شود چیزی مانند c:\\windows\\c:\\windows\\fonts\\tahoma.ttf . به همین جهت این فونت یافت نشده و ثبت نمی‌شود (چون دوبار system root در آن وجود دارد).
- بله؛ قدرت پردازش CSS در XML Worker آن خیلی بهتر است از HTML Worker.
- در مورد میزان چرخش جدول، RunDirection = PdfWriter.RUN_DIRECTION_RTL را با حالت LTR هم تست کنید (PdfWriter.RUN_DIRECTION_LTR ).
مطالب
استخراج متن از فایل‌های PDF توسط iTextSharp
پیشنیاز
نحوه ذخیره شدن متن در فایل‌های PDF

حتما نیاز است پیشنیاز فوق را یکبار مطالعه کنید تا علت خروجی‌های متفاوتی را که در ادامه ملاحظه خواهید نمود، بهتر مشخص شوند. همچنین فایل PDF ایی که مورد بررسی قرار خواهد گرفت، همان فایلی است که توسط متد writePdf ذکر شده در پیشنیاز تهیه شده است.

دو کلاس متفاوت برای استخراج متن از فایل‌های PDF در iTextSharp وجود دارند:
الف) SimpleTextExtractionStrategy

using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;

namespace TestReaders
{
    class Program
    {
        private static void readPdf1()
        {
            var reader = new PdfReader("test.pdf");
            int intPageNum = reader.NumberOfPages;
            for (int i = 1; i <= intPageNum; i++)
            {
               var text = PdfTextExtractor.GetTextFromPage(reader, i, new SimpleTextExtractionStrategy());
                File.WriteAllText("page-" + i + "-text.txt", text);
            }
            reader.Close();
        }

        static void Main(string[] args)
        {
            readPdf1();
        }
    }
}
مثال فوق، متن موجود در تمام صفحات یک فایل PDF را در فایل‌های txt جداگانه‌ای ثبت می‌کند. برای نمونه اگر از PDF پیشنیاز یاد شده استفاده کنیم، خروجی آن به نحو زیر خواهد بود:
 Test
ld Wor llo He
Hello People
علت آن نیز پیشتر بررسی گردید. متن، در این فایل ویژه در مختصات خاصی ترسیم شده است. حاصل از دیدگاه خواننده نهایی بسیار خوانا است؛ اما خروجی hello world متنی جالبی از آن استخراج نمی‌شود. SimpleTextExtractionStrategy دقیقا بر اساس همان عملگر‌های Tj و همچنین منابع صفحه، عبارات را یافته و سر هم می‌کند.


ب) LocationTextExtractionStrategy

همان مثال قبل را درنظر بگیرید، اینبار به شکل زیر:
        private static void readPdf2()
        {
            var reader = new PdfReader("test.pdf");
            int intPageNum = reader.NumberOfPages;
            for (int i = 1; i <= intPageNum; i++)
            {
                var text = PdfTextExtractor.GetTextFromPage(reader, i, new LocationTextExtractionStrategy());
                File.WriteAllText("page-" + i + "-text.txt", text);
            }
            reader.Close();
        }
کلاس LocationTextExtractionStrategy هوشمند‌تر عمل کرده و بر اساس عملگرهای هندسی یک فایل PDF، سعی می‌کند جملات و حروف را کنار هم قرار دهد و در نهایت خروجی متنی بهتری را تولید کند. برای نمونه اینبار خروجی متنی حاصل به صورت زیر خواهد بود:
 Test
Hello World
Hello People
این خروجی با آنچه که در صفحه نمایش داده می‌شود تطابق دارد.


استخراج متون فارسی از فایل‌های PDF توسط iTextSharp

روش‌های فوق با PDFهای فارسی هم کار می‌کنند اما خروجی حاصل آن مفهوم نیست و نیاز به پردازش ثانوی دارد. ابتدا مثال زیر را درنظر بگیرید:
        static void writePdf2()
        {
            using (var document = new Document(PageSize.A4))
            {
                var writer = PdfWriter.GetInstance(document, new FileStream("test.pdf", FileMode.Create));
                document.Open();

                FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");
                var tahoma = FontFactory.GetFont("tahoma", BaseFont.IDENTITY_H);

                ColumnText.ShowTextAligned(
                            canvas: writer.DirectContent,
                            alignment: Element.ALIGN_CENTER,
                            phrase: new Phrase("تست می‌شود", tahoma),
                            x: 100,
                            y: 100,
                            rotation: 0,
                            runDirection: PdfWriter.RUN_DIRECTION_RTL,
                            arabicOptions: 0);                
            }

            Process.Start("test.pdf");
        }
از متد فوق، برای تولید یک فایل PDF که متنی فارسی را نمایش می‌دهد استفاده خواهیم کرد. اگر متد readPdf2 را که به همراه LocationTextExtractionStrategy تعریف شده است، بر روی فایل حاصل فراخوانی کنیم، خروجی آن به صورت زیر خواهد بود:
ﺩﻮﺷﻲﻣ ﺖﺴﺗ
برای تبدیل آن به یونیکد خواهیم داشت:
        private static void readPdf2()
        {
            var reader = new PdfReader("test.pdf");
            int intPageNum = reader.NumberOfPages;
            for (int i = 1; i <= intPageNum; i++)
            {
                var text = PdfTextExtractor.GetTextFromPage(reader, i, new LocationTextExtractionStrategy());                
                text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(text));
                File.WriteAllText("page-" + i + "-text.txt", text, Encoding.UTF8);
            }
            reader.Close();
        }
اکنون خروجی ثبت شده در فایل متنی حاصل به صورت زیر است:
 ﺩﻮﺷﻲﻣ ﺖﺴﺗ
دقیقا به همان نحوی است که iTextSharp و اکثر تولید کننده‌های PDF فارسی از آن استفاده می‌کنند و اصطلاحا چرخاندن حروف یا تولید Glyph mirrors صورت می‌گیرد. روش‌های زیادی برای چرخاندن حروف وجود دارند. در ادامه از روشی استفاده خواهیم کرد که خود ویندوز در کارهای داخلی‌اش از آن استفاده می‌کند:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;

namespace TestReaders
{
    [SuppressUnmanagedCodeSecurity]
    class GdiMethods
    {
        [DllImport("GDI32.dll")]
        public static extern bool DeleteObject(IntPtr hgdiobj);

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern uint GetCharacterPlacement(IntPtr hdc, string lpString, int nCount, int nMaxExtent, [In, Out] ref GcpResults lpResults, uint dwFlags);

        [DllImport("GDI32.dll")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
    }

    [StructLayout(LayoutKind.Sequential)]
    struct GcpResults
    {
        public uint lStructSize;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpOutString;
        public IntPtr lpOrder;
        public IntPtr lpDx;
        public IntPtr lpCaretPos;
        public IntPtr lpClass;
        public IntPtr lpGlyphs;
        public uint nGlyphs;
        public int nMaxFit;
    }

    public class UnicodeCharacterPlacement
    {
        const int GcpReorder = 0x0002;
        GCHandle _caretPosHandle;
        GCHandle _classHandle;
        GCHandle _dxHandle;
        GCHandle _glyphsHandle;
        GCHandle _orderHandle;

        public Font Font { set; get; }

        public string Apply(string lines)
        {
            if (string.IsNullOrWhiteSpace(lines))
                return string.Empty;

            return Apply(lines.Split('\n')).Aggregate((s1, s2) => s1 + s2);
        }

        public IEnumerable<string> Apply(IEnumerable<string> lines)
        {
            if (Font == null)
                throw new ArgumentNullException("Font is null.");

            if (!hasUnicodeText(lines))
                return lines;

            var graphics = Graphics.FromHwnd(IntPtr.Zero);
            var hdc = graphics.GetHdc();
            try
            {
                var font = (Font)Font.Clone();
                var hFont = font.ToHfont();
                var fontObject = GdiMethods.SelectObject(hdc, hFont);
                try
                {
                    var results = new List<string>();
                    foreach (var line in lines)
                        results.Add(modifyCharactersPlacement(line, hdc));
                    return results;
                }
                finally
                {
                    GdiMethods.DeleteObject(fontObject);
                    GdiMethods.DeleteObject(hFont);
                    font.Dispose();
                }
            }
            finally
            {
                graphics.ReleaseHdc(hdc);
                graphics.Dispose();
            }
        }

        void freeResources()
        {
            _orderHandle.Free();
            _dxHandle.Free();
            _caretPosHandle.Free();
            _classHandle.Free();
            _glyphsHandle.Free();
        }

        static bool hasUnicodeText(IEnumerable<string> lines)
        {
            return lines.Any(line => line.Any(chr => chr >= '\u00FF'));
        }

        void initializeResources(int textLength)
        {
            _orderHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
            _dxHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
            _caretPosHandle = GCHandle.Alloc(new int[textLength], GCHandleType.Pinned);
            _classHandle = GCHandle.Alloc(new byte[textLength], GCHandleType.Pinned);
            _glyphsHandle = GCHandle.Alloc(new short[textLength], GCHandleType.Pinned);
        }

        string modifyCharactersPlacement(string text, IntPtr hdc)
        {
            var textLength = text.Length;
            initializeResources(textLength);
            try
            {
                var gcpResult = new GcpResults
                {
                    lStructSize = (uint)Marshal.SizeOf(typeof(GcpResults)),
                    lpOutString = new String('\0', textLength),
                    lpOrder = _orderHandle.AddrOfPinnedObject(),
                    lpDx = _dxHandle.AddrOfPinnedObject(),
                    lpCaretPos = _caretPosHandle.AddrOfPinnedObject(),
                    lpClass = _classHandle.AddrOfPinnedObject(),
                    lpGlyphs = _glyphsHandle.AddrOfPinnedObject(),
                    nGlyphs = (uint)textLength,
                    nMaxFit = 0
                };
                var result = GdiMethods.GetCharacterPlacement(hdc, text, textLength, 0, ref gcpResult, GcpReorder);
                return result != 0 ? gcpResult.lpOutString : text;
            }
            finally
            {
                freeResources();
            }
        }
    }
}
از کلاس فوق در هر برنامه‌ای که راست به چپ را به نحو صحیحی پشتیبانی نمی‌کند، می‌توان استفاده کرد؛ خصوصا برنامه‌های گرافیکی.
در اینجا برای اصلاح متد readPdf2 خواهیم داشت:
        private static void readPdf2()
        {
            var reader = new PdfReader("test.pdf");
            int intPageNum = reader.NumberOfPages;
            for (int i = 1; i <= intPageNum; i++)
            {
                var text = PdfTextExtractor.GetTextFromPage(reader, i, new LocationTextExtractionStrategy());
                text = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(text));
                text = new UnicodeCharacterPlacement
                {
                    Font = new System.Drawing.Font("Tahoma", 12)
                }.Apply(text);
                File.WriteAllText("page-" + i + "-text.txt", text, Encoding.UTF8);
            }
            reader.Close();
        }
اگر خروجی متد اصلاح شده فوق را بررسی کنیم، دقیقا به «تست می‌شود» خواهیم رسید.

سؤال: آیا این روش با تمام PDFهای فارسی کار می‌کند؟
پاسخ: خیر! همانطور که در پیشنیاز مطلب جاری عنوان شد، در یک حالت خاص، PDF writer می‌تواند شماره Glyphها را کاملا عوض کرده و در فایل PDF نهایی ثبت کند. خروجی حاصل در برنامه Adobe reader خوانا است، چون نمایش را بر اساس اطلاعات هندسی Glyphها انجام می‌دهد؛ اما خروجی متنی آن به نوعی obfuscated است چون مثلا حرف A آن به کاراکتر مرسوم دیگری نگاشت شده است.
نظرات مطالب
راه اندازی StimulSoft Report در ASP.NET MVC
اگر تولید کننده‌ی PDF آن در حد و اندازه‌های iTextSharp باشد (که نیست) و اگر قابلیت Font Selector آن‌را اضافه کرده باشد (که اینطور نیست)، می‌تواند از چندین فونت استفاده کند: «iTextSharp و استفاده از قلم‌های محدود فارسی». در غیر اینصورت تنها راه حل موجود برای این موارد استفاده از یک قلم فارسی کامل است.
پاسخ به بازخورد‌های پروژه‌ها
نمایش چندی خطی یک فیلد
یک نکته
اگر PdfGrid را دستی درست کنید و همچنین از Phrase بجای FontSelector استفاده شود، متد FixWeakCharacters با آن مشکلی ندارد. یعنی Phrase حروف نامرئی یونیکد را حذف نمی‌کند. اما مشکل Phrase این است که با فونت‌های محدود فارسی درست کار نمی‌کند. اگر در متن شما ترکیب فارسی و انگلیسی بود، فقط حروف فارسی را خواهید دید و نه انگلیسی را. به همین جهت از FontSelector در پشت صحنه استفاده شده.
نظرات مطالب
نمایش گرادیان در iTextSharp