我是iText7的新手,但是对大多数概念都有相当的了解。
我想为我的PDF创建一个目录(TOC),并在其网站上找到以下Java示例: https://developers.itextpdf.com/content/itext-7-examples/itext-7-bookmarks-tocs/toc-first-page
将程序转换为c#可以处理普通文本,但是当在表格中的单元格中包含段落时,它将不再起作用。
此外,我无法使“重新订购”页面部分正常工作,有什么想法吗?
编辑:找到一种重新排列页面顺序的方法
using iText.IO.Font.Constants;
using iText.IO.Source;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Action;
using iText.Kernel.Pdf.Canvas.Draw;
using iText.Kernel.Pdf.Navigation;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Hyphenation;
using iText.Layout.Layout;
using iText.Layout.Properties;
using iText.Layout.Renderer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ConsoleApp2
{
class Program
{
public const string Src = @"C:\Users\mgs\source\repos\ConsoleApp2\text.txt";
public const string Dest = @"C:\Users\mgs\source\repos\ConsoleApp2\table_of_contents.pdf";
static void Main(string[] args)
{
byte[] bytes = CreatePdf();
File.WriteAllBytes(Dest, bytes);
}
public static byte[] CreatePdf()
{
using (var s = new MemoryStream())
{
PdfDocument pdf = new PdfDocument(new PdfWriter(s));
pdf.GetCatalog().SetPageMode(PdfName.UseOutlines);
PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
Document document = new Document(pdf);
document.SetTextAlignment(TextAlignment.JUSTIFIED)
.SetHyphenation(new HyphenationConfig("en", "uk", 3, 3))
.SetFont(font)
.SetFontSize(11);
// parse text to PDF
Dictionary<string, KeyValuePair<string, int>> toc = WritePdf(pdf, bold, document);
document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
// create table of contents
int startToc = CreateToc(pdf, bold, document, toc);
int tocPages = pdf.GetNumberOfPages() - startToc;
document.Close();
PdfDocument srcDoc = new PdfDocument(new PdfReader(new RandomAccessSourceFactory().CreateSource(s.ToArray()), new ReaderProperties()));
using (MemoryStream ms = new MemoryStream())
{
PdfDocument resultDoc = new PdfDocument(new PdfWriter(ms));
resultDoc.InitializeOutlines();
var pages = ReorderPages(tocPages, srcDoc, startToc);
srcDoc.CopyPagesTo(pages, resultDoc);
resultDoc.Close();
srcDoc.Close();
byte[] bytes = ms.ToArray();
return bytes;
}
}
}
private static List<int> ReorderPages(int tocPages, PdfDocument pdf, int startToc)
{
int allpages = pdf.GetNumberOfPages();
var pages = new List<int>();
for (var i = 0; i <= tocPages; i++)
{
pages.Add(startToc + i);
}
for (var i = 0; i < allpages - (tocPages + 1); i++)
{
pages.Add(i + 1);
}
return pages;
}
private static int CreateToc(PdfDocument pdf, PdfFont bold, Document document, Dictionary<string, KeyValuePair<string, int>> toc)
{
int startToc = pdf.GetNumberOfPages();
var p = new Paragraph()
.SetFont(bold)
.Add("Table of Contents")
.SetDestination("toc");
document.Add(p);
toc.Remove(toc.First().Key);
List<TabStop> tabstops = new List<TabStop>();
tabstops.Add(new TabStop(580, TabAlignment.RIGHT, new DottedLine()));
foreach (KeyValuePair<string, KeyValuePair<string, int>> entry in toc)
{
KeyValuePair<string, int> text = entry.Value;
string entryKey = entry.Key;
string textKey = text.Key;
string textValue = text.Value.ToString();
p = new Paragraph()
.AddTabStops(tabstops)
.Add(textKey)
.Add(new Tab())
.Add(textValue)
.SetAction(PdfAction.CreateGoTo(entryKey));
document.Add(p);
}
return startToc;
}
private static Dictionary<string, KeyValuePair<string, int>> WritePdf(PdfDocument pdf, PdfFont bold, Document document)
{
string[] lines = File.ReadAllLines(Src);
var title = true;
var counter = 0;
PdfOutline outline = null;
var toc = new Dictionary<string, KeyValuePair<string, int>>();
var t = new Table(1);
foreach (string line in lines)
{
var p = new Paragraph(line);
p.SetKeepTogether(true);
if (title)
{
string name = "title" + counter++;
outline = CreateOutline(outline, pdf, line, name);
KeyValuePair<string, int> titlePage = new KeyValuePair<string, int>(line, pdf.GetNumberOfPages());
p.SetFont(bold)
.SetFontSize(12)
.SetKeepWithNext(true)
.SetDestination(name)
.SetNextRenderer(new UpdatePageRenderer(p, titlePage));
title = false;
//TODO:
var c = new Cell().Add(p);
t.AddCell(c);
//document.Add(p);
toc.Add(name, titlePage);
}
else
{
p.SetFirstLineIndent(36);
if (string.IsNullOrWhiteSpace(line))
{
p.SetMarginBottom(12);
title = true;
}
else
{
p.SetMarginBottom(0);
}
//TODO:
var c = new Cell().Add(p);
t.AddCell(c);
//document.Add(p);
}
}
//TODO:
document.Add(t);
return toc;
}
protected class UpdatePageRenderer : ParagraphRenderer
{
protected KeyValuePair<string, int> Entry;
public UpdatePageRenderer(Paragraph modelElement, KeyValuePair<string, int> entry) : base(modelElement)
{
Entry = entry;
}
public override LayoutResult Layout(LayoutContext layoutContext)
{
var result = base.Layout(layoutContext);
int pageNumber = layoutContext.GetArea().GetPageNumber();
Entry = new KeyValuePair<string, int>(Entry.Key, pageNumber);
return result;
}
}
public static PdfOutline CreateOutline(PdfOutline outline, PdfDocument pdf, String title, String name)
{
if (outline == null)
{
outline = pdf.GetOutlines(false);
outline = outline.AddOutline(title);
outline.AddDestination(PdfDestination.MakeDestination(new PdfString(name)));
return outline;
}
var kid = outline.AddOutline(title);
kid.AddDestination(PdfDestination.MakeDestination(newPdfString(name)));
return outline;
}
}
}
答案 0 :(得分:1)
所有页码均为0
的原因是,您在尝试获取页码之前没有添加任何内容。
突出显示WritePdf()
函数的重要部分:
private static Dictionary < string, KeyValuePair < string, int >> WritePdf(PdfDocument pdf, PdfFont bold, Document document) {
...
var t = new Table(1);
...
foreach (string line in lines) {
//Adding content to the table and getting the page numbers.
//Content is *not* added to the document yet, so pdf.GetNumberOfPages() returns 0
}
...
document.add(t); //Finally adding the table to the document after it is too late
}
您可以通过先将表格添加到文档中,然后定期将其刷新,从而稍微改变一下方法:
private static Dictionary < string, KeyValuePair < string, int >> WritePdf(PdfDocument pdf, PdfFont bold, Document document) {
...
var t = new Table(1, true); //True stands for "large table" which allows us to flush the content.
document.Add(t); //Immediately add the document to the table
...
foreach (string line in lines) {
//Add whatever you want to the table
t.flush(); //But make sure to flush the content so the page numbers are correct
}
...
t.complete() //Tell the renderer that the table will not have any more content added to it.
}
这将是您的更新功能:
private static Dictionary<string, KeyValuePair<string, int>> WritePdf(PdfDocument pdf, PdfFont bold, Document document)
{
string[] lines = File.ReadAllLines(SRC);
var title = true;
var counter = 0;
PdfOutline outline = null;
var toc = new Dictionary<string, KeyValuePair<string, int>>();
var t = new Table(1, true);
document.Add(t);
foreach (string line in lines) {
var p = new Paragraph(line);
p.SetKeepTogether(true);
if (title) {
string name = "title" + counter++;
outline = CreateOutline(outline, pdf, line, name);
KeyValuePair<string, int> titlePage = new KeyValuePair<string, int>(line, pdf.GetNumberOfPages());
p.SetFont(bold)
.SetFontSize(12)
.SetKeepWithNext(true)
.SetDestination(name)
.SetNextRenderer(new UpdatePageRenderer(p, titlePage));
title = false;
//TODO:
//document.Add(p);
toc.Add(name, titlePage);
}
else {
p.SetFirstLineIndent(36);
if (string.IsNullOrWhiteSpace(line)) {
p.SetMarginBottom(12);
title = true;
}
else {
p.SetMarginBottom(0);
}
//TODO:
var c = new Cell().Add(p);
t.AddCell(c);
//document.Add(p);
}
t.Flush();
}
t.Complete();
//TODO:
return toc;
}