如何在iTextSharp中创建目录

时间:2016-08-19 11:10:45

标签: c# pdf itext

我需要使用页码创建内容表,但我不知道如何。下一个格式:

heading1 ----------------page number  
  subHeading1---------------page number
  subHeading2---------------page number  
heading2-----------------page number  

我读了几篇文章并且没有理解。特别是,我的意思是this文章,其中"命名目的地"和" GoTo行动"我认为对我有用,但我不知道它在iTextSharp中是如何做的。

在我的代码中,我很少有" Chapter"和"部分",我想拿它并创建TOC。我怎么理解,我需要使用PdfPageEventHelper和OnChapter。

3 个答案:

答案 0 :(得分:3)

你可能已经通过名字自己实现了这个,但为了完整起见,我自己做了一个小例子。

请查看CreateTOC示例。它使用一些随机文本创建PDF:

enter image description here

您可以清楚地看到标题下的标题和内容。在我们添加了所有内容后,我们开始一个新页面,并添加一个目录:

enter image description here

目录由一系列键值对组成,其中键是标题,值是页码。我们在页面事件中创建此列表:

public class TOCEvent extends PdfPageEventHelper {

    protected List<SimpleEntry<String, Integer>> toc = new ArrayList<>();

    @Override
    public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
        toc.add(new SimpleEntry(text, writer.getPageNumber()));
    }

    public List getTOC() {
        return toc;
    }
}

我们使用此页面事件:

public void createPdf(String dest) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
    TOCEvent event = new TOCEvent();
    writer.setPageEvent(event);
    document.open();
    for (int i = 0; i < 10; i++) {
        String title = "This is title " + i;
        Chunk c = new Chunk(title, titleFont);
        c.setGenericTag(title);
        document.add(new Paragraph(c));
        for (int j = 0; j < 50; j++) {
            document.add(new Paragraph("Line " + j + " of title " + i));
        }
    }
    document.newPage();
    document.add(new Paragraph("Table of Contents", titleFont));
    Chunk dottedLine = new Chunk(new DottedLineSeparator());
    List<SimpleEntry<String, Integer>> entries = event.getTOC();
    Paragraph p;
    for (SimpleEntry<String, Integer> entry : entries) {
        p = new Paragraph(entry.getKey());
        p.add(dottedLine);
        p.add(String.valueOf(entry.getValue()));
        document.add(p);
    }
    document.close();
}

首先,我们创建一个事件实例,并将其声明给作者:

TOCEvent event = new TOCEvent();
writer.setPageEvent(event);

我们使用setGenericTag()标记标题:

String title = "This is title " + i;
Chunk c = new Chunk(title, titleFont);
c.setGenericTag(title);
document.add(new Paragraph(c));

完成添加内容后,我们会收到所有条目:

List<SimpleEntry<String, Integer>> entries = event.getTOC();

我们遍历此列表并为每个条目撰写Paragraph

for (SimpleEntry<String, Integer> entry : entries) {
    p = new Paragraph(entry.getKey());
    p.add(dottedLine);
    p.add(String.valueOf(entry.getValue()));
    document.add(p);
}

没有人可以说这很难。事件类只需不到10行代码。添加对副标题的支持将添加一些行,但这也不难。这是建立树结构的问题,并在必要时引入一些缩进。

答案 1 :(得分:3)

谢谢你的例子,我需要在C#和多列中使用它,所以我重写了这个例子,如下所示:

namespace GerarPDF
{
public class GerarPDF
{
    public const String DEST = "results/example.pdf";

    public GerarPDF()
    {
        FileInfo file = new FileInfo(String.Concat(AppDomain.CurrentDomain.BaseDirectory, @"/", DEST));
        file.Directory.Create();
        this.createPdf(file.FullName);
    }

    public void createPdf(String dest)
    {
        FileStream fs = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);

        Document document = new Document(PageSize.LETTER);
        PdfWriter writer = PdfWriter.GetInstance(document, fs);
        document.Open();

        TOCEvent evento = new TOCEvent();
        writer.PageEvent = evento;

        for (int i = 0; i < 10; i++)
        {
            String title = "This is title " + i;
            Chunk c = new Chunk(title, new Font());
            c.SetGenericTag(title);
            document.Add(new Paragraph(c));
            for (int j = 0; j < 50; j++)
            {
                document.Add(new Paragraph("Line " + j + " of title " + i + " page: " + writer.PageNumber));
            }
        }
        document.NewPage();
        document.Add(new Paragraph("Table of Contents", new Font()));
        Chunk dottedLine = new Chunk(new DottedLineSeparator());
        List<PageIndex> entries = evento.getTOC();

        MultiColumnText columns = new MultiColumnText();
        columns.AddRegularColumns(72, 72 * 7.5f, 24, 2);

        Paragraph p;
        for (int i = 0; i < 10; i++)
        {
            foreach (PageIndex pageIndex in entries)
            {
                Chunk chunk = new Chunk(pageIndex.Text);
                chunk.SetAction(PdfAction.GotoLocalPage(pageIndex.Name, false));
                p = new Paragraph(chunk);
                p.Add(dottedLine);

                chunk = new Chunk(pageIndex.Page.ToString());
                chunk.SetAction(PdfAction.GotoLocalPage(pageIndex.Name, false));
                p.Add(chunk);

                columns.AddElement(p);
            }
        }
        document.Add(columns);

        document.Close();
    }

    public class TOCEvent : PdfPageEventHelper
    {
        protected int counter = 0;
        protected List<PageIndex> toc = new List<PageIndex>();

        public override void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, string text)
        {
            String name = "dest" + (counter++);
            int page = writer.PageNumber;
            toc.Add(new PageIndex() { Text = text, Name = name, Page = page });
            writer.DirectContent.LocalDestination(name, new PdfDestination(PdfDestination.FITH, rect.GetTop(0)));
        }

        public List<PageIndex> getTOC()
        {
            return toc;
        }
    }
}

public class PageIndex
{
    public string Text { get; set; }
    public string Name { get; set; }
    public int Page { get; set; }
}
}

答案 2 :(得分:0)

此代码片段可以是递归的,基本概念是:

List<PdfPCell> celdas = new List<PdfPCell>();
string urlSection=String.empty;    
var estatus = new Phrase();
estatus.Leading = 25;
if (streams != null && streams.Any())
    primero = streams.FirstOrDefault(x => x.Id == enlace.Id);
if (primero != null)
    urlSection = primero.UrlSection;

//For the code and generate hyperlink:
Chunk espacioTab = new Chunk(" " + enlace.Name, baseFontBig );

espacioTab = Visor.Servicios.GeneracionPDF.PDFUtils.GenerarVinculo(" " + enlace.Name, urlSection, baseFontBig);
estatus.Add(espacioTab);
if (incluirPaginado)
{

   if (primero != null)
       actualPage = primero.TotalPages;
   else
       actualPage = 0;

///This is important, generate dots like "...." to chunk end 
    estatus.Add(new Chunk(new iTextSharp.text.pdf.draw.DottedLineSeparator()));

    var linkPagina = new Chunk(actualPage.ToString());
    linkPagina = Visor.Servicios.GeneracionPDF.PDFUtils.GenerarVinculo(actualPage.ToString(), urlSection, baseFontBig );
    estatus.Add(linkPagina);
    resultado.paginaFinal = actualPage;
}

//This is for add to your cell or table
PdfPCell rightCell = new PdfPCell()
{
    Border = PdfPCell.NO_BORDER,
    Colspan = 3,
    PaddingLeft = espacioInicial.Length,
    ExtraParagraphSpace = 10,
};
rightCell.AddElement(estatus);
celdas.Add(rightCell);

并创建一个新方法,这将创建一个超链接,您可以在需要时调用

/*Generar Vinculo (create hyperlink)**/
public static Chunk GenerarVinculo(String tituloMostrar, string urlDirecion, iTextSharp.text.Font fuente)
{
    Chunk espacioTab = new Chunk();
    try
    {
        if (String.IsNullOrEmpty(urlDirecion))
        urlDirecion = "Indice de Contenido";

        espacioTab = new Chunk(tituloMostrar, fuente);
        var accion = PdfAction.GotoLocalPage(urlDirecion, false);
        espacioTab.SetAction(accion);
    }                
    catch (Exception error) { }
    return espacioTab;
}

希望可以帮助某人