如何使用 MigraDoc 定义 PDF 大纲
How to Define a PDF Outline Using MigraDoc
我在使用 MigraDoc 时注意到,如果我添加具有任何标题样式(例如 "Heading1")的段落,文档大纲中会自动放置一个条目。我的问题是,如何在文档大纲中添加条目而不显示文档中的文本?这是我的代码示例:
var document = new Document();
var section = document.AddSection();
// The following line adds an entry to the document outline, but it also
// adds a line of text to the current section. How can I add an
// entry to the document outline without adding any text to the page?
var paragraph = section.AddParagraph("TOC Level 1", "Heading1");
我使用了一个 hack:在白色背景上添加字体大小为 0.001 左右的白色文本以获得用户实际上看不到的轮廓。
要获得完美的解决方案,请混合使用 PDFsharp 和 MigraDoc 代码。这个 hack 对我有用,而且更容易实现。
我在阅读 ThomasH 的回答后意识到我已经在混合使用 PDFSharp 和 MigraDoc 代码。由于我使用的是 PdfDocumentRenderer,因此我能够向该渲染器的 PdfDocument 属性 添加自定义大纲。这是我最终创建自定义大纲的示例:
var document = new Document();
// Populate the MigraDoc document here
...
// Render the document
var renderer = new PdfDocumentRenderer(false, PdfFontEmbedding.Always)
{
Document = document
};
renderer.RenderDocument();
// Create the custom outline
var pdfSharpDoc = renderer.PdfDocument;
var rootEntry = pdfSharpDoc.Outlines.Add(
"Level 1 Header", pdfSharpDoc.Pages[0]);
rootEntry.Outlines.Add("Level 2 Header", pdfSharpDoc.Pages[1]);
// Etc.
// Save the document
pdfSharpDoc.Save(outputStream);
我有一个稍微不那么被黑的方法。这是基本方法:
1) 添加书签,将书签字段object和大纲条目名称保存到列表中。不要设置段落 .OutlineLevel(或设置为 bodytext)
// Defined previously
List<dynamic> Bookmarks = new List<dynamic>();
// In your bookmarking method, P is a Paragraph already created somewhere
Bookmarks.Add(new { Bookmark = P.AddBookmark("C1"), Name = "Chapter 1", Depth = 0 });
2) 在 Migradoc 布局结束时,在渲染之前,准备页面
pdfwriter.PrepareRenderPages();
3) 建立书签的parent的parent(这将是一个段落)和页面(页面将被初始化为-1)
的字典
var Pages = Bookmarks.Select(x=> ((BookmarkField)x).Bookmark.Parent.Parent).ToDictionary(x=>x, x=>-1);
4) 现在通过遍历每个页面上的 object 来填充这些页面,找到匹配项
for (int i = 0; i < pdfwriter.PageCount; i++)
foreach (var s in pdfwriter.DocumentRenderer.GetDocumentObjectsFromPage(i).Where(x=> Pages.ContainsKey(x))
Pages[s] = i-1;
5) 您现在已经有了一本书签 parent 的 parent 到页码的字典,您可以使用它直接将大纲添加到 PDFSharp 文档中。这也迭代了 depth-tree,所以你可以有嵌套的轮廓
foreach(dynamic d in Bookmarks)
{
var o = pdfwriter.PdfDocument.Outlines;
for(int i=0;i<d.Depth;i++)
o = o.Last().Outlines;
BookmarkField BK = d.Bookmark;
int PageNumber = Pages[BK.Parent.Parent];
o.Add(d.Name, pdfwriter.PdfDocument.Pages[PageNumber], true, PdfOutlineStyle.Regular);
}
我在使用 MigraDoc 时注意到,如果我添加具有任何标题样式(例如 "Heading1")的段落,文档大纲中会自动放置一个条目。我的问题是,如何在文档大纲中添加条目而不显示文档中的文本?这是我的代码示例:
var document = new Document();
var section = document.AddSection();
// The following line adds an entry to the document outline, but it also
// adds a line of text to the current section. How can I add an
// entry to the document outline without adding any text to the page?
var paragraph = section.AddParagraph("TOC Level 1", "Heading1");
我使用了一个 hack:在白色背景上添加字体大小为 0.001 左右的白色文本以获得用户实际上看不到的轮廓。
要获得完美的解决方案,请混合使用 PDFsharp 和 MigraDoc 代码。这个 hack 对我有用,而且更容易实现。
我在阅读 ThomasH 的回答后意识到我已经在混合使用 PDFSharp 和 MigraDoc 代码。由于我使用的是 PdfDocumentRenderer,因此我能够向该渲染器的 PdfDocument 属性 添加自定义大纲。这是我最终创建自定义大纲的示例:
var document = new Document();
// Populate the MigraDoc document here
...
// Render the document
var renderer = new PdfDocumentRenderer(false, PdfFontEmbedding.Always)
{
Document = document
};
renderer.RenderDocument();
// Create the custom outline
var pdfSharpDoc = renderer.PdfDocument;
var rootEntry = pdfSharpDoc.Outlines.Add(
"Level 1 Header", pdfSharpDoc.Pages[0]);
rootEntry.Outlines.Add("Level 2 Header", pdfSharpDoc.Pages[1]);
// Etc.
// Save the document
pdfSharpDoc.Save(outputStream);
我有一个稍微不那么被黑的方法。这是基本方法:
1) 添加书签,将书签字段object和大纲条目名称保存到列表中。不要设置段落 .OutlineLevel(或设置为 bodytext)
// Defined previously
List<dynamic> Bookmarks = new List<dynamic>();
// In your bookmarking method, P is a Paragraph already created somewhere
Bookmarks.Add(new { Bookmark = P.AddBookmark("C1"), Name = "Chapter 1", Depth = 0 });
2) 在 Migradoc 布局结束时,在渲染之前,准备页面
pdfwriter.PrepareRenderPages();
3) 建立书签的parent的parent(这将是一个段落)和页面(页面将被初始化为-1)
的字典var Pages = Bookmarks.Select(x=> ((BookmarkField)x).Bookmark.Parent.Parent).ToDictionary(x=>x, x=>-1);
4) 现在通过遍历每个页面上的 object 来填充这些页面,找到匹配项
for (int i = 0; i < pdfwriter.PageCount; i++)
foreach (var s in pdfwriter.DocumentRenderer.GetDocumentObjectsFromPage(i).Where(x=> Pages.ContainsKey(x))
Pages[s] = i-1;
5) 您现在已经有了一本书签 parent 的 parent 到页码的字典,您可以使用它直接将大纲添加到 PDFSharp 文档中。这也迭代了 depth-tree,所以你可以有嵌套的轮廓
foreach(dynamic d in Bookmarks)
{
var o = pdfwriter.PdfDocument.Outlines;
for(int i=0;i<d.Depth;i++)
o = o.Last().Outlines;
BookmarkField BK = d.Bookmark;
int PageNumber = Pages[BK.Parent.Parent];
o.Add(d.Name, pdfwriter.PdfDocument.Pages[PageNumber], true, PdfOutlineStyle.Regular);
}