پاسخ به بازخورد‌های پروژه‌ها
نمایش متن ساده
برای نمایش متن ساده از همان iTextSharp و افزونه‌های آن می‌شود استفاده کرد. برای تبدیل HTML به PDF قبلا راهنمایی در سایت تهیه شده. همچنین نکات فارسی نویسی با iTextSharp هم تمام و کمال در سایت بررسی و مستند شده‌اند.
مطالب
رسم گراف

کتابخانه‌های زیادی برای رسم گراف وجود دارند منجمله mxGraph که برای استفاده غیرتجاری رایگان و سورس باز است. mxGraph نگارش‌های PHP ، Java‌ و JavaScript ایی نیز دارد که به همراه بسته مربوطه ارائه می‌شوند.
پس از دریافت آن، در فولدری به نام dotnet می‌توانید سورس کتابخانه مربوط به دات نت فریم ورک آن‌را دریافت کنید.
فایل پروژه‌ی VS.Net را در آن فولدر نخواهید یافت. حتی آن‌را کامپایل هم نکرده‌اند. (احتمالا به این دلیل که کسی نپرسد این پروژه با چه محصولی تولید شده و آیا لایسنس استفاده از آن را دارید یا خیر. این هم یک روش است ...)
برای کامپایل آن، یک پروژه library جدید را در VS.Net آغاز کرده و پوشه‌های موجود در پوشه‌ی dotnet را به آن افزوده و سپس آن‌را کامپایل کنید تا فایل mxGraph.dll تولید شود.

یک مثال ساده از نحوه‌ی استفاده‌ی آن به صورت زیر است که فایل test.png را تولید خواهد کرد.
using System;
using System.Drawing;
using System.Windows.Forms;
using com.mxgraph;
using System.Drawing.Imaging;

void Test1()
{
// Creates graph with model
mxGraph graph = new mxGraph();
Object parent = graph.GetDefaultParent();

// Adds cells into the graph
graph.Model.BeginUpdate();
try
{
Object v1 = graph.InsertVertex(parent, null, "سلام", 20, 20, 80, 30, "strokeColor=#FFCF8A;fillColor=#FFCF8A;gradientColor=white;fontBold=true;fontFamily=tahoma;rounded=true;shadow=true;shape=ellipse");
Object v2 = graph.InsertVertex(parent, null, "!دنیای ظالم", 200, 150, 80, 30, "rounded=true;shadow=true;fontFamily=tahoma");
Object e1 = graph.InsertEdge(parent, null, "e1", v1, v2, "fontFamily=tahoma");
}
finally
{
graph.Model.EndUpdate();
}

mxCellRenderer.CreateImage(graph, null, 1,
Color.White, true, null).Save("test.png", ImageFormat.Png);
}




و یا اگر قصد داشته باشید که از آن در ASP.Net استفاده کنید، یک generic handler را به پروژه خود افزوده (مثلا ImageHandler.ashx) و کد آن‌را برای مثال به صورت زیر تغییر دهید:

using System;
using System.Web;
using com.mxgraph;
using System.Drawing;
using System.Web.Services;
using System.IO;
using System.Drawing.Imaging;

namespace test
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// Creates graph with model
mxGraph graph = new mxGraph();
Object parent = graph.GetDefaultParent();

// Adds cells into the graph
graph.Model.BeginUpdate();
try
{
Object v1 = graph.InsertVertex(parent, null, "سلام", 20, 20, 80, 30, "strokeColor=#FFCF8A;fillColor=#FFCF8A;gradientColor=white;fontBold=true;fontFamily=tahoma;rounded=true;shadow=true;shape=ellipse");
Object v2 = graph.InsertVertex(parent, null, "!دنیای ظالم", 200, 150, 80, 30, "rounded=true;shadow=true;fontFamily=tahoma");
Object e1 = graph.InsertEdge(parent, null, "e1", v1, v2, "fontFamily=tahoma");
}
finally
{
graph.Model.EndUpdate();
}

Image image = mxCellRenderer.CreateImage(graph, null, 1, Color.White, true, null);

// Render BitMap Stream Back To Client
MemoryStream memStream = new MemoryStream();
image.Save(memStream, ImageFormat.Png);

memStream.WriteTo(context.Response.OutputStream);
}

public bool IsReusable
{
get
{
return false;
}
}
}

}
اکنون نحوه استفاده از این handler در یک صفحه وب به صورت زیر است:
<img src="ImageHandler.ashx" />

اشتراک‌ها
یک قلم چگونه طراحی می‌شود؟
بررسی مراحل تولید یک قلم از نمونه‌های اولیه تا تبدیل به نسخه‌ی دیجیتال و انتقال آن به نرم افزارهای مرتبط
یک قلم چگونه طراحی می‌شود؟
نظرات مطالب
تعیین Fallback font برای قلم‌های فارسی در WPF
این موارد در آخرین لینکی که در متن مقاله است مفصل توضیح داده شده.
- بله. امکان تعریف چندین قلم وجود دارد.
- ذکر قسمت نام فایل اختیاری است (مثلا می‌شود به یک پوشه هم ارجاع داد). اما باید font family حتما ذکر شود.
نظرات مطالب
آیا دیتابیس مورد استفاده در NHibernate با نگاشت‌های تعریف شده همخوانی دارد؟
بله، این کد برای چک کردن خود بانک است. آیا فیلدی فراموش نشده. آیا جدولی از قلم نیفتاده.
موردی هم که اشاره کردید جزو ابزارهای NHibernate است و شبیه به همین کار را انجام می‌دهد : (+)
نظرات مطالب
آشنایی با NHibernate - قسمت سوم
شاید جایی رو از قلم انداخته‌اید (solution کامل شما باید برای دیباگ موجود باشد).
سورس کامل قابل دریافت این موارد در پایان قسمت چهارم ارائه شده. به آن مراجعه کنید.
پاسخ به بازخورد‌های پروژه‌ها
استفاده از فونت های مختلف در گزارش
بدون بودن کدهای شما نمی‌شود نظر داد. تصویر فوق مربوط به کجا است؟ هدر سفارشی؟ اگر سفارشی است تنظیمات قلم فوق روی آن تاثیری ندارد. در حالت سفارشی همه چیز را باید خودتان از صفر مدیریت کنید.
نظرات نظرسنجی‌ها
کدامیک از قلم‌های فارسی ذیل خواناتر هستند؟
من از صمیم استفاده می‌کنم و تا الان کاربران راضی بودن، طی یک نظرسنجی داخلی نزدیک به ۳۳۰۰ نفر از کاربرانم از این قلم راضی بودن و برخی هم سلیقه‌ای ناراضی .
نظرات مطالب
تعیین Fallback font برای قلم‌های فارسی در WPF
به این صورت کار می‌کنه:


<TextBlock 
            Text="نمایش مخلوطی از متن فارسی و متن English با هم"
            Margin="7"
            FontFamily="Fonts/irsans.ttf#Iranian Sans, Comic Sans Ms"
            FontSize="25"
            FlowDirection="RightToLeft"
            VerticalAlignment="Top" HorizontalAlignment="Center"  />

مطالب
فشرده سازی حجم فایل‌های PDF توسط iTextSharp
پیشتر در سایت جاری مطلبی را در مورد «بهینه سازی حجم فایل PDF تولیدی در حین کار با تصاویر در iTextSharp» مطالعه کرده‌اید. خلاصه آن به این نحو است که می‌توان در یک فایل PDF، ده‌ها تصویر را که تنها به یک فایل فیزیکی اشاره می‌کنند قرار داد. به این ترتیب حجم فایل نهایی تا حد بسیار قابل ملاحظه‌ای کاهش می‌یابد. البته آن مطلب در مورد تولید یک فایل PDF جدید صدق می‌کند. اما در مورد فایل‌های PDF موجود و از پیش آماده شده چطور؟


سؤال: آیا در فایل PDF ما تصاویر تکراری وجود دارند؟

نحوه یافتن تصاویر تکراری موجود در یک فایل PDF را به کمک iTextSharp در کدهای ذیل ملاحظه می‌کنید:
        public static int FindDuplicateImagesCount(string pdfFileName)
        {
            int count = 0;
            var pdf = new PdfReader(pdfFileName);

            var md5 = new MD5CryptoServiceProvider();
            var enc = new UTF8Encoding();
            var imagesHashList = new List<string>();

            int intPageNum = pdf.NumberOfPages;
            for (int i = 1; i <= intPageNum; i++)
            {
                var page = pdf.GetPageN(i);
                var resources = PdfReader.GetPdfObject(page.Get(PdfName.RESOURCES)) as PdfDictionary;
                if (resources == null) continue;

                var xObject = PdfReader.GetPdfObject(resources.Get(PdfName.XOBJECT)) as PdfDictionary;
                if (xObject == null) continue;

                foreach (var name in xObject.Keys)
                {
                    var pdfObject = xObject.Get(name);
                    if (!pdfObject.IsIndirect()) continue;

                    var imgObject = PdfReader.GetPdfObject(pdfObject) as PdfDictionary;
                    if (imgObject == null) continue;

                    var subType = PdfReader.GetPdfObject(imgObject.Get(PdfName.SUBTYPE)) as PdfName;
                    if (subType == null) continue;

                    if (!PdfName.IMAGE.Equals(subType)) continue;

                    byte[] imageBytes = PdfReader.GetStreamBytesRaw((PRStream)imgObject);
                    var md5Hash = enc.GetString(md5.ComputeHash(imageBytes));

                    if (!imagesHashList.Contains(md5Hash))
                    {
                        imagesHashList.Add(md5Hash);
                    }
                    else
                    {
                        Console.WriteLine("Found duplicate image @page: {0}.", i);
                        count++;
                    }
                }
            }

            pdf.Close();
            return count;
        }
در این کد، از قابلیت‌های سطح پایین PdfReader استفاده شده است. یک فایل PDF از پیش آماده، توسط این شیء گشوده شده و سپس محتویات تصاویر آن یافت می‌شوند. در ادامه هش MD5 آن‌ها محاسبه و با یکدیگر مقایسه می‌شوند. اگر هش تکراری یافت شد، یعنی تصویر یافت شده تکراری است و این فایل قابلیت بهینه سازی و کاهش حجم (قابل ملاحظه‌ای) را دارا می‌باشد.


سؤال: چگونه اشیاء تکراری یک فایل PDF را حذف کنیم؟

کلاسی در iTextSharp به نام PdfSmartCopy وجود دارد که شبیه به عملیات فوق را انجام داده و یک کپی سبک از هر صفحه را تهیه می‌کند. سپس می‌توان این کپی‌ها را کنار هم قرار داد و فایل اصلی را مجددا بازسازی کرد:
    public class PdfSmartCopy2 : PdfSmartCopy
    {
        public PdfSmartCopy2(Document document, Stream os)
            : base(document, os)
        { }

        /// <summary>
        /// This is a forgotten feature in iTextSharp 5.3.4. 
        /// Actually its PdfSmartCopy is useless without this!
        /// </summary>
        protected override PdfIndirectReference CopyIndirect(PRIndirectReference inp, bool keepStructure, bool directRootKids)
        {
            return base.CopyIndirect(inp);
        }
    }

        public static void RemoveDuplicateObjects(string inFile, string outFile)
        {
            var document = new Document();
            var copy = new PdfSmartCopy2(document, new FileStream(outFile, FileMode.Create));
            document.Open();

            var reader = new PdfReader(inFile);

            var n = reader.NumberOfPages;
            for (int page = 0; page < n; )
            {
                copy.AddPage(copy.GetImportedPage(reader, ++page));
            }
            copy.FreeReader(reader);            

            document.Close();
        }
به نظر در نگارش iTextSharp 5.3.4 نویسندگان این کتابخانه اندکی فراموش کرده‌اند که باید تعدادی متد دیگر را نیز override کنند! به همین جهت کلاس PdfSmartCopy2 را مشاهده می‌کنید (اگر از نگارش‌های پایین‌تر استفاده می‌کنید، نیازی به آن نیست).
استفاده از آن هم ساده است. در متد RemoveDuplicateObjects، ابتدا هر صفحه موجود توسط متد GetImportedPage دریافت شده و به وهله‌ای از PdfSmartCopy اضافه می‌شود. در پایان کار، فایل نهایی تولیدی، حاوی عناصر تکراری نخواهد بود. احتمالا برنامه‌های PDF compressor تجاری را در گوشه و کنار اینترنت دیده‌اید. متد RemoveDuplicateObjects دقیقا همان کار را انجام می‌دهد. 
اگر علاقمند هستید که متد فوق را آزمایش کنید یک فایل جدید PDF را به صورت زیر ایجاد نمائید:
        private static void CreateTestFile()
        {
            using (var pdfDoc = new Document(PageSize.A4))
            {
                var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
                pdfDoc.Open();

                var table = new PdfPTable(new float[] { 1, 2 });
                table.AddCell(Image.GetInstance("01.png"));
                table.AddCell(Image.GetInstance("01.png"));
                pdfDoc.Add(table);
            }
        }
در این فایل دو وهله از تصویر 01.png به صفحه اضافه شده‌اند. بنابراین دقیقا دو تصویر در فایل نهایی تولیدی وجود خواهد داشت.
سپس متد RemoveDuplicateObjects را روی test.pdf تولید شده فراخوانی کنید. حجم فایل حاصل تقریبا نصف خواهد شد. از این جهت که PdfSmartCopy توانسته است بر اساس هش MD5 موجود در فایل PDF نهایی، موارد تکراری را یافته و ارجاعات را تصحیح کند.
در شکل زیر ساختار فایل test.pdf اصلی را ملاحظه می‌کنید. در اینجا img1 و img0 به دو stream متفاوت اشاره می‌کنند:


در شکل زیر همان test.pdf را پس از بکارگیری PDFSmartCopy ملاحظه می‌کنید:

اینبار دو تصویر داریم که هر دو به یک stream اشاره می‌کنند. تصاویر فوق به کمک برنامه iText RUPS تهیه شده‌اند.