TagTextLayout.cs
// 完毕:
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Pdf.Structure;
using GrapeCity.Documents.Pdf.MarkedContent;
namespace DsPdfWeb.Demos.Basics
{
// 此示例展示了如何创建带标签(结构化)的 PDF 并附加
// 用于渲染的 TextLayout 中各个段落的标签
// 它们放在一起,在页面之间分开。
// 生成文档的代码与PaginatedText中使用的代码类似,
// 但添加了标签。
// 要查看/探索标签,请在 Adobe Acrobat Pro 中打开文档并转到
// 查看 |导航面板|标签。
public class TagTextLayout
{
public int CreatePDF(Stream stream)
{
var doc = new GcPdfDocument();
// 创建一个 Part 元素,它将包含 P(段落)元素:
var sePart = new StructElement("Part");
doc.StructTreeRoot.Children.Add(sePart);
// 创建并设置 TextLayout 来呈现段落:
var tl = new TextLayout(72);
tl.DefaultFormat.Font = StandardFonts.Times;
tl.DefaultFormat.FontSize = 12;
tl.FirstLineIndent = 72 / 2;
tl.MaxWidth = doc.PageSize.Width;
tl.MaxHeight = doc.PageSize.Height;
tl.MarginAll = tl.Resolution;
// 附加文本(20 段,这样一页就放不下)
// (请注意,TextLayout 将“\r\n”解释为段落分隔符):
//
// 获取文本(20段):
var text = Common.Util.LoremIpsum(20);
// 为了标记各个段落,我们需要将文本拆分为段落,
// 并使用每个段落格式的 Tag 属性(与 PDF 标签无关,
// 它只是可以与 TextFormat 关联的任意数据)以添加
// 段落的索引:
var pars = text.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < pars.Length; ++i)
{
var tf = new TextFormat(tl.DefaultFormat) { Tag = i };
tl.AppendLine(pars[i], tf);
}
// 布局文本:
tl.PerformLayout(true);
// 使用分割选项来提供寡妇/孤儿控制:
var to = new TextSplitOptions(tl)
{
MinLinesInFirstParagraph = 2,
MinLinesInLastParagraph = 2,
};
// TextLayoutHandler 实现了 ITextLayoutHandler,它
// 允许在呈现文本时对其进行标记:
var tlh = new TextLayoutHandler() { ParentElement = sePart };
// 在循环中,分割并渲染文本:
while (true)
{
// 'rest' 将接受不适合的文本:
var splitResult = tl.Split(to, out TextLayout rest);
var page = doc.Pages.Add();
var g = page.Graphics;
// 告诉 TextLayoutHandler 我们在哪个页面:
tlh.Page = page;
// ..并将其与图形相关联:
g.TextLayoutHandler = tlh;
// 绘制适合当前页面的文本,然后前进到下一页,除非我们完成:
g.DrawTextLayout(tl, PointF.Empty);
if (splitResult != SplitResult.Split)
break;
tl = rest;
}
// 将文档标记为已标记:
doc.MarkInfo.Marked = true;
// 完毕:
doc.Save(stream);
return doc.Pages.Count;
}
// 允许在 TextLayout 呈现内容时标记内容的自定义类:
private class TextLayoutHandler : ITextLayoutHandler
{
private int _tagIndex;
private int _currentParagraphIndex = -1;
private StructElement _currentparagraphElement;
public StructElement ParentElement;
public Page Page;
public void TextTagBegin(GcPdfGraphics graphics, TextLayout textLayout, object tag)
{
int paragraphIndex;
if (tag is int)
paragraphIndex = (int)tag;
else
paragraphIndex = -1;
StructElement paragraphElement;
if (_currentParagraphIndex == paragraphIndex)
{
paragraphElement = _currentparagraphElement;
}
else
{
if (paragraphIndex >= 0)
{
paragraphElement = new StructElement("P");
ParentElement.Children.Add(paragraphElement);
_currentparagraphElement = paragraphElement;
_currentParagraphIndex = paragraphIndex;
}
else
{
paragraphElement = null;
_currentparagraphElement = paragraphElement;
_currentParagraphIndex = paragraphIndex;
}
}
//
if (paragraphElement != null)
{
graphics.BeginMarkedContent(new TagMcid("P", _tagIndex));
var mcil = new McrContentItemLink();
mcil.MCID = _tagIndex;
mcil.Page = Page;
paragraphElement.ContentItems.Add(mcil);
_tagIndex++;
}
}
public void TextTagEnd(GcPdfGraphics graphics, TextLayout textLayout, object tag)
{
if (_currentparagraphElement != null)
graphics.EndMarkedContent();
}
public void AddTextArea(RectangleF bounds)
{
}
}
}
}