۱۳۹۰/۰۹/۰۱

ساخت يك گزارش ساز به كمك iTextSharp و Open Office


iTextSharp پايه كار با فايل‌هاي PDF را ارائه مي‌دهد اما ابزاري را جهت ساده‌تر سازي توليد فايل‌هاي PDF به همراه ندارد؛ هر چند مثلا امكان تبديل HTML به PDF را دارا است اما بايد گفت: «تا حدودي البته». اگر نياز باشد جدولي را ايجاد كنيم بايد كد نويسي كرد، اگر نياز باشد تصويري اضافه شود به همين ترتيب و الي آخر. البته اين را هم بايد در نظر داشت كه كد نويسي انعطاف قابل توجهي را در اختيار برنامه نويس قرار مي‌دهد؛ شايد به همين دليل اين روزها مباحث «Code first» بيشتر مورد توجه برنامه نويس‌ها است، تا مباحث «Wizard first» يك دهه قبل!
اما باز هم داشتن يك طراح بد نيست و مي‌تواند در كاهش مدت زمان توليد نهايي يك فايل PDF مؤثر باشد. براي اين منظور مي‌توان از برنامه‌ي رايگان و معروف Open office استفاده كرد. توسط آن مي‌توان يك فرم PDF را طراحي و سپس فيلدهاي آن‌را (اين قالب تهيه شده را) با iTextSharp پر كرد. اين مورد مي‌تواند براي تهيه گزارش‌هايي كه تهيه آن‌ها با ابزارهاي متداول گزارش سازي عموما ميسر نيست،‌ بسيار مناسب باشد.


طراحي يك فرم PDF با استفاده از برنامه Open Office

آخرين نگارش برنامه Open office را از اينجا مي‌توانيد دريافت كنيد و آنچنان حجمي هم ندارد؛ حدودا 154 مگابايت است.
پس از نصب و اجراي برنامه، حداقل به دو طريق مي‌توان يك فرم جديد را شروع كرد:
الف) آغاز يك XML Form document جديد در Open office سبب خواهد شد كه نوارهاي ابزار طراحي فرم، مانند قرار دادن TextBox ، CheckBox و غيره به صورت خودكار ظاهر شوند.
ب) و يا آغاز يك سند معمولي و سپس مراجعه به منوي View->Toolbars->Form Controls هم همان حالت را به همراه خواهد داشت.


در اينجا براي طراحي يك گزارش يا فرم جديد تنها كافي است همانند روش‌هاي متداول تهيه يك سند معمولي رفتار كنيم و مواردي را كه قرار است توسط iTextSharp مقدار دهي كنيم، با كنترل‌هاي نوار ابزار Form آن بر روي صفحه قرار دهيم كه نمونه‌ي ساده آن‌را در شكل زير ملاحظه مي‌كنيد:


براي گزارش‌هاي فارسي بهتر است Alignment يك كنترل به Right تنظيم شود و Border به حالت Without frame مقدار دهي گردد. نام اين كنترل را هم بخاطر بسپاريد و يا تغيير دهيد. از اين نام‌ها در iTextSharp استفاده خواهيم كرد. (صفحه خواص فوق با دوبار كليك بر روي يك كنترل قرار گرفته بر روي فرم ظاهر مي‌شود)

مرحله بعد، تبديل اين فرم به فايل PDF است. كليك بر روي دكمه تهيه خروجي به صورت PDF در نوار ابزار اصلي آن براي اينكار كفايت مي‌كند. اين گزينه در منوي File نيز موجود است.


فرم‌هاي PDF تهيه شده در اينجا، فقط خواندني هستند. مثلا يك كاربر مي‌تواند آن‌ها را پر كرده و چاپ كند. اما ما از آن‌ها در ادامه به عنوان قالب گزارشات استفاده خواهيم كرد. بنابراين جهت ويرايش فرم‌هاي تهيه شده بهتر است فايل‌هاي اصلي Open Office مرتبط را نيز درجايي نگهداري كرد و هر بار پس از ويرايش، نياز است تا خروجي جديد PDF آن‌ها تهيه شود.


استفاده از iTextSharp جهت مقدار دهي فيلدهاي يك فرم PDF

در ادامه مي‌خواهيم اين قالب گزارشي را كه تهيه كرديم با كمك iTextSharp پر كرده و يك فايل PDF جديد تهيه كنيم. سورس كامل اينكار را در ذيل مشاهده مي‌كنيد:


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

namespace PdfForm
{
    class Program
    {
        //روش صحيح ثبت و معرفي فونت در اين كتابخانه
        public static iTextSharp.text.Font GetTahoma()
        {
            var fontName = "Tahoma";
            if (!FontFactory.IsRegistered(fontName))
            {
                var fontPath = Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\tahoma.ttf";
                FontFactory.Register(fontPath);
            }
            return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        }

        static void Main(string[] args)
        {
            string fileNameExisting = @"form.pdf";
            string fileNameNew = @"newform.pdf";

            using (var existingFileStream = new FileStream(fileNameExisting, FileMode.Open))
            using (var newFileStream = new FileStream(fileNameNew, FileMode.Create))
            {
                var pdfReader = new PdfReader(existingFileStream);
                using (var stamper = new PdfStamper(pdfReader, newFileStream))
                {
                    //نكته مهم جهت كار با اطلاعات فارسي
                    //در غيراينصورت شاهد ثبت اطلاعات نخواهيد بود
                    stamper.AcroFields.AddSubstitutionFont(GetTahoma().BaseFont);

                    //form.Fields.Keys = تمام فيلدهاي موجود در فرم
                    var form = stamper.AcroFields;                   

                    //مقدار دهي فيلدهاي فرم
                    form.SetField("TextBox1", "مقدار1");
                    form.SetField("TextBox2", "مقدار2");

                    // "Yes" and "Off" are valid values here
                    form.SetField("Check Box 1", "Yes");

                    // "" and "Off" are valid values here
                    form.SetField("Option Button 1", "");

                    // نحوه مقدار دهي ليست
                    form.SetListOption("ListBox1", new[] { "1مقدار يك", "مقدار دو1" }, null);
                    form.SetField("ListBox1", null);

                    // به اين ترتيب فرم ديگر توسط كاربر قابل ويرايش نخواهد بود
                    //stamper.PartialFormFlattening --> جهت غيرقابل ويرايش نمودن فيلدي مشخص
                    stamper.FormFlattening = true;

                    stamper.Close();
                    pdfReader.Close();
                }
            }

            Process.Start("newform.pdf");
        }
    }
}

توضيحات:
چون در اينجا فايل PDF، از پيش تهيه شده است، پس بايد از اشياء PdfReader و PdfStamper جهت خواندن و نوشتن اطلاعات در آن‌ها استفاده كرد. سپس توسط شيء stamper.AcroFields مي‌توان به اين فيلدها يا همان كنترل‌هايي كه در برنامه‌ي Open office بر روي فرم قرار داديم، دسترسي پيدا كنيم.
در ابتدا نياز است فونت اين فيلدها توسط متد AddSubstitutionFont مقدار دهي شود. اين مورد براي گزارش‌هاي فارسي الزامي است؛ در غيراينصورت متني را در خروجي مشاهده نخواهيد كرد.
ادامه كار هم مشخص است. توسط متد form.SetField مقداري را به كنترل‌هاي قرار گرفته بر روي فرم نسبت مي‌دهيم. آرگومان اول آن نام كنترل است و آرگومان دوم، مقدار مورد نظر مي‌باشد. اگر كنترل CheckBox را بر روي صفحه قرار داديد، تنها مقدارهاي Yes و Off را مي‌پذيرد (آن هم با توجه به اينكه به كوچكي و بزرگي حروف حساس است). اگر يك Radio button يا در اينجا Option button را بر روي فرم قرار داديد، تنها مقدارهاي خالي و Off را قبول خواهد كرد. نحوه‌ي مقدار دهي يك ليست هم در اينجا ذكر شده است.
در پايان چون نمي‌خواهيم كاربر نهايي قادر به ويرايش اطلاعات باشد، FormFlattening را true خواهيم كرد و به اين ترتيب، كنترل‌ها فقط خواندني خواهند شد. البته اگر همانطور كه ذكر شد، border كنترل‌ها را در حين طراحي حذف كنيد، PDF نهايي توليدي يكپارچه و يك دست به نظر مي‌رسد و اصلا مشخص نخواهد بود كه اين فايل پيشتر يك فرم قابل پر كردن بوده است.