Isjhar Kautsar

Software Engineer
  • Home
  • Blog
  • Works
  • About
Social
Contact

isjhar@gmail.com

Membuat Daftar Isi dengan iText di .NET

Kemarin saya dapat klien yang minta dibuatkan fitur yang dapat menulis konten ke dalam PDF. Salah satu kebutuhannya adalah halaman daftar isi di halaman depan berkas. Pada artikel ini saya akan membagikan bagaimana membuatnya menggunakan iText di .NET. Versi .NET yang saya gunakan adalah versi 8.

Tahap pertama, buat program Console menggunakan di Visual Studio. Di Program.cs buat script untuk membuat satu berkas kosong PDF dengan iText.

using iText.IO.Font.Constants;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class TableOfContents
    {
        public static readonly string DEST = "table_of_contents.pdf";

        public static void Main(string[] args)
        {
            FileInfo file = new FileInfo(DEST);

            file.Directory?.Create();

            new TableOfContents().ManipulatePdf(DEST);
        }

        public void ManipulatePdf(String dest)
        {
            PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            
            Document document = new Document(pdfDoc);
            document
                .SetTextAlignment(TextAlignment.JUSTIFIED)
                .SetFont(font)
                .SetFontSize(11);            

            document.Close();
        }        
    }
}

Buat PageNumberEventHandler class yang berfungsi untuk menuliskan nomor halaman di bagian footer.

using iText.IO.Font.Constants;
using iText.Kernel.Events;
using iText.Kernel.Font;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class PageNumberEventHandler : IEventHandler
    {
        private readonly PdfDocument _pdf;

        public PageNumberEventHandler(PdfDocument pdf)
        {
            _pdf = pdf;
        }

        public void HandleEvent(Event currentEvent)
        {
            PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
            PdfPage page = docEvent.GetPage();
            int pageNumber = _pdf.GetPageNumber(page);

            Rectangle pageSize = page.GetPageSize();
            PdfCanvas canvas = new PdfCanvas(page.NewContentStreamAfter(), page.GetResources(), _pdf);
            Canvas footerCanvas = new Canvas(canvas, pageSize);

            Paragraph p = new Paragraph($"{pageNumber}")
                .SetFont(PdfFontFactory.CreateFont(StandardFonts.HELVETICA))
                .SetFontSize(10)
                .SetTextAlignment(TextAlignment.CENTER);

            footerCanvas
                .ShowTextAligned(p, pageSize.GetWidth() / 2, 20, TextAlignment.CENTER);
            footerCanvas.Close();
        }
    }
}

Set event handler di Program.cs dengan PageNumberEventHandler agar dieksekusi setiap pindah halaman.

using iText.IO.Font.Constants;
using iText.Kernel.Events;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class TableOfContents
    {
        public static readonly string DEST = "table_of_contents.pdf";

        public static void Main(string[] args)
        {
            FileInfo file = new FileInfo(DEST);

            file.Directory?.Create();

            new TableOfContents().ManipulatePdf(DEST);
        }

        public void ManipulatePdf(string dest)
        {
            PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));

            var pageNumberEventHandler = new PageNumberEventHandler(pdfDoc);
            pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, pageNumberEventHandler);

            Document document = new Document(pdfDoc);
            document
                .SetTextAlignment(TextAlignment.JUSTIFIED)
                .SetFont(font)
                .SetFontSize(11);

            document.Close();
        }
    }
}

Buat variable _toc dengan tipe KeyValuePair untuk menyimpan informasi halaman title dan nomor halaman yang nanti akan ditampilkan di halaman daftar isi. Kemudian buat prosedur AddPage untuk menambahkan halaman. Buat 3 halaman dengan AddPage sebagai contoh.

using iText.IO.Font.Constants;
using iText.Kernel.Events;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class TableOfContents
    {
        public static readonly string DEST = "table_of_contents.pdf";

        private readonly List<KeyValuePair<string, int>> _toc = new List<KeyValuePair<string, int>>();

        public static void Main(string[] args)
        {
            FileInfo file = new FileInfo(DEST);

            file.Directory?.Create();

            new TableOfContents().ManipulatePdf(DEST);
        }

        public void ManipulatePdf(string dest)
        {
            PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));

            var pageNumberEventHandler = new PageNumberEventHandler(pdfDoc);
            pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, pageNumberEventHandler);

            Document document = new Document(pdfDoc);
            document
                .SetTextAlignment(TextAlignment.JUSTIFIED)
                .SetFont(font)
                .SetFontSize(11);

            AddPage(pdfDoc, document, _toc, "Page 1");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 2");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 3");
            document.Add(new AreaBreak());

            document.Close();
        }

        private void AddPage(PdfDocument pdfDoc, Document document, List<KeyValuePair<string, int>> toc, string text)
        {
            var p = new Paragraph(text);
            p.SetKeepTogether(true);
            p.SetFontSize(12)
                .SetKeepWithNext(true);

            document.Add(p);

            KeyValuePair<string, int> titlePage = new KeyValuePair<string, int>(text, pdfDoc.GetNumberOfPages());

            toc.Add(titlePage);
        }
    }
}

Buat prosedur CreateToc yang berfungsi untuk membuat halaman daftar isi berdasarkan nilai yang tersimpan di variabel _toc. Panggil prosedur ini di prosedur ManipulatePdf.

using iText.IO.Font.Constants;
using iText.Kernel.Events;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Draw;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class TableOfContents
    {
        public static readonly string DEST = "table_of_contents.pdf";

        private readonly List<KeyValuePair<string, int>> _toc = new List<KeyValuePair<string, int>>();

        public static void Main(string[] args)
        {
            FileInfo file = new FileInfo(DEST);

            file.Directory?.Create();

            new TableOfContents().ManipulatePdf(DEST);
        }

        public void ManipulatePdf(string dest)
        {
            PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));

            var pageNumberEventHandler = new PageNumberEventHandler(pdfDoc);
            pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, pageNumberEventHandler);

            Document document = new Document(pdfDoc);
            document
                .SetTextAlignment(TextAlignment.JUSTIFIED)
                .SetFont(font)
                .SetFontSize(11);

            AddPage(pdfDoc, document, _toc, "Page 1");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 2");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 3");
            document.Add(new AreaBreak());

            CreateToc(document);

            document.Close();
        }

        private void AddPage(PdfDocument pdfDoc, Document document, List<KeyValuePair<string, int>> toc, string text)
        {
            var p = new Paragraph(text);
            p.SetKeepTogether(true);
            p.SetFontSize(12)
                .SetKeepWithNext(true);

            document.Add(p);

            KeyValuePair<string, int> titlePage = new KeyValuePair<string, int>(text, pdfDoc.GetNumberOfPages());

            toc.Add(titlePage);
        }

        private void CreateToc(Document document)
        {
            PdfFont bold = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);

            // Create table of contents
            Paragraph p = new Paragraph("Table of Contents")
                .SetFont(bold)
                .SetDestination("toc");

            document.Add(p);

            List<TabStop> tabStops = new List<TabStop>();
            tabStops.Add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
            foreach (KeyValuePair<string, int> entry in _toc)
            {
                p = new Paragraph()
                    .AddTabStops(tabStops)
                    .Add(entry.Key)
                    .Add(new Tab())
                    .Add(entry.Value.ToString());

                document.Add(p);
            }
        }
    }
}

Sampai disini, halaman daftar isi sudah berhasil dibuat tetapi berada di halaman terakhir. Untuk memindahkan halaman daftar isi ini ke halaman awal gunakan fungsi MovePage pada class PdfDocument seperti kode dibawah ini.

using iText.IO.Font.Constants;
using iText.Kernel.Events;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Draw;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

namespace TocFirstPageExample
{
    public class TableOfContents
    {
        public static readonly string DEST = "table_of_contents.pdf";

        private readonly List<KeyValuePair<string, int>> _toc = new List<KeyValuePair<string, int>>();

        public static void Main(string[] args)
        {
            FileInfo file = new FileInfo(DEST);

            file.Directory?.Create();

            new TableOfContents().ManipulatePdf(DEST);
        }

        public void ManipulatePdf(string dest)
        {
            PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));

            var pageNumberEventHandler = new PageNumberEventHandler(pdfDoc);
            pdfDoc.AddEventHandler(PdfDocumentEvent.END_PAGE, pageNumberEventHandler);

            Document document = new Document(pdfDoc);
            document
                .SetTextAlignment(TextAlignment.JUSTIFIED)
                .SetFont(font)
                .SetFontSize(11);

            AddPage(pdfDoc, document, _toc, "Page 1");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 2");
            document.Add(new AreaBreak());

            AddPage(pdfDoc, document, _toc, "Page 3");
            document.Add(new AreaBreak());

            CreateToc(document);

            // Move the table of contents to the first page
            pageNumberEventHandler.IsCreatingToc = true;
            int tocPageNumber = pdfDoc.GetNumberOfPages();
            pdfDoc.MovePage(tocPageNumber, 1);

            document.Close();
        }

        private void AddPage(PdfDocument pdfDoc, Document document, List<KeyValuePair<string, int>> toc, string text)
        {
            var p = new Paragraph(text);
            p.SetKeepTogether(true);
            p.SetFontSize(12)
                .SetKeepWithNext(true);

            document.Add(p);

            KeyValuePair<string, int> titlePage = new KeyValuePair<string, int>(text, pdfDoc.GetNumberOfPages());

            toc.Add(titlePage);
        }

        private void CreateToc(Document document)
        {
            PdfFont bold = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);

            // Create table of contents
            Paragraph p = new Paragraph("Table of Contents")
                .SetFont(bold)
                .SetDestination("toc");

            document.Add(p);

            List<TabStop> tabStops = new List<TabStop>();
            tabStops.Add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
            foreach (KeyValuePair<string, int> entry in _toc)
            {
                p = new Paragraph()
                    .AddTabStops(tabStops)
                    .Add(entry.Key)
                    .Add(new Tab())
                    .Add(entry.Value.ToString());

                document.Add(p);
            }
        }
    }
}

Demikian cara membuat halaman daftar isi menggunakan iText library di .NET. Keseluruhan kode dari artikel ini dapat di akses di GitHub – isjhar/itext-toc-example: Example code of first page Table of Content using iText in .NET.

isjhar . 22 May 2025 . 0 comments

.NET Programming

0 Comments

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked*