TagTextLayout.cs
- //
- // This code is part of Document Solutions for PDF demos.
- // Copyright (c) MESCIUS inc. All rights reserved.
- //
- 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
- {
- // This sample shows how to create tagged (structured) PDF and attach
- // tags to individual paragraphs in a TextLayout that is used to render
- // them together, splitting between pages.
- // The code generating the document is similar to that used in PaginatedText,
- // but adds tags.
- // To see/explore the tags, open the document in Adobe Acrobat Pro and go to
- // View | Navigation Panels | Tags.
- public class TagTextLayout
- {
- public int CreatePDF(Stream stream)
- {
- var doc = new GcPdfDocument();
-
- // Create a Part element, it will contain P (paragraph) elements:
- var sePart = new StructElement("Part");
- doc.StructTreeRoot.Children.Add(sePart);
-
- // Create and set up a TextLayout to render paragraphs:
- 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;
- //
- // Append the text (20 paragraphs so they would not fit on a single page)
- // (note that TextLayout interprets "\r\n" as paragraph delimiter):
- //
- // Get the text (20 paragraphs):
- var text = Common.Util.LoremIpsum(20);
- // In order to tag the individual paragraphs, we need to split the text into paragraphs,
- // and use each paragraph format's Tag property (which is not related to PDF tags,
- // it is just an arbitrary data that can be associated with a TextFormat) to add the
- // paragraph's index to the paragraph:
- 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);
- }
-
- // Layout the text:
- tl.PerformLayout(true);
- // Use split options to provide widow/orphan control:
- var to = new TextSplitOptions(tl)
- {
- MinLinesInFirstParagraph = 2,
- MinLinesInLastParagraph = 2,
- };
- // TextLayoutHandler implements ITextLayoutHandler, which
- // allows tagging the text as it is rendered:
- var tlh = new TextLayoutHandler() { ParentElement = sePart };
-
- // In a loop, split and render the text:
- while (true)
- {
- // 'rest' will accept the text that did not fit:
- var splitResult = tl.Split(to, out TextLayout rest);
- var page = doc.Pages.Add();
- var g = page.Graphics;
- // Tell the TextLayoutHandler which page we're on:
- tlh.Page = page;
- // ..and associate it with the graphics:
- g.TextLayoutHandler = tlh;
- // Draw the text that fits on the current page, and advance to next page unless we're done:
- g.DrawTextLayout(tl, PointF.Empty);
- if (splitResult != SplitResult.Split)
- break;
- tl = rest;
- }
- // Mark document as tagged:
- doc.MarkInfo.Marked = true;
-
- // Done:
- doc.Save(stream);
- return doc.Pages.Count;
- }
-
- // Custom class that allows tagging content as it is rendered by 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)
- {
- }
- }
- }
- }
-