ReadTagsTableData.cs
//
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Pdf.TextMap;
using GrapeCity.Documents.Pdf.Structure;
using GrapeCity.Documents.Pdf.Recognition.Structure;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
namespace DsPdfWeb.Demos
{
// 構造タグを使用してテーブルを検索し、そのデータを読み取ります。
public class ReadTagsTableData
{
private TextFormat _tf, _tfHdr, _tfPgHdr;
private float _margin = 72;
public int CreatePDF(Stream stream)
{
// テキストフォーマットを設定します。
_tf = new TextFormat()
{
Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "ipag.ttc")),
FontSize = 9,
ForeColor = Color.Black
};
_tfHdr = new TextFormat(_tf)
{
FontBold = true,
FontSize = 11,
ForeColor = Color.DarkBlue
};
_tfPgHdr = new TextFormat(_tf)
{
FontSize = 11,
ForeColor = Color.Gray
};
// 結果のPDFを生成します。
var doc = new GcPdfDocument();
using (var s = File.OpenRead(Path.Combine("Resources", "PDFs", "C1Olap-QuickStart.pdf")))
{
var source = new GcPdfDocument();
source.Load(s);
PrintAllTables(doc, source);
}
// PDFを保存します。
doc.Save(stream);
return doc.Pages.Count;
}
private void PrintAllTables(GcPdfDocument doc, GcPdfDocument source)
{
// LogicalStructureと最上位の親要素を取得します。
LogicalStructure ls = source.GetLogicalStructure();
if (ls == null || ls.Elements == null || ls.Elements.Count == 0)
{
// 構造タグが見つからない場合:
Common.Util.AddNote("ドキュメントに構造タグが見つかりませんでした。", doc.Pages.Add());
return;
}
// ルート要素:
Element root = ls.Elements[0];
// すべてのテーブルを検索して出力します。
var tables = new List<(TextLayout, Page)>();
root.Children.ToList().FindAll(e_ => e_.StructElement.Type == "Table").ForEach(t_ => tables.Add(PrintTable(t_)));
// 見つかったページごとにテーブルをまとめます。
var tablesByPage = tables.GroupBy(t_ => t_.Item2.Index);
// 各ページごとに、そのページにあるすべてのテーブルを出力し、
// その後に参照用として元のページを出力します。
foreach (var tbp in tablesByPage)
{
// 抽出されたテーブルデータを出力するページです。
var pgTables = doc.NewPage();
// 参照用の元ページを出力するページです。
var pgSrc = doc.NewPage();
// 元のページを出力します。
tbp.First().Item2.Draw(pgSrc.Graphics, pgSrc.Bounds);
// ページヘッダーを追加します。
pgSrc.Graphics.DrawString($"元のPDFの {tbp.First().Item2.Index + 1} ページ目",
_tfPgHdr, new RectangleF(0, 0, pgSrc.Size.Width, _margin), TextAlignment.Center, ParagraphAlignment.Center, false);
//
float maxHeight = pgTables.Size.Height - _margin * 2;
float y = _margin;
// すべてのテーブルデータを出力します。
// 簡略化のため、すべてのテーブルデータが1ページに収まることを想定しています。
foreach (var t in tbp)
{
t.Item1.MaxHeight = maxHeight;
t.Item1.MaxWidth = pgTables.Size.Width - _margin * 2;
pgTables.Graphics.DrawTextLayout(t.Item1, new PointF(_margin, y));
maxHeight -= t.Item1.ContentHeight + _margin;
y += t.Item1.ContentHeight + _margin;
}
}
}
private (TextLayout, Page) PrintTable(Element e)
{
if (e.Type != "Table")
throw new Exception($"予期しないエラー:要素タイプは'Table'でなければなりませんが、'{e.Type}'になっています。");
List<List<IList<ITextParagraph>>> table = new List<List<IList<ITextParagraph>>>();
int maxCols = 0;
// タイプがTR(テーブル行)であるすべての子要素を選択します。
void SelectRows(IReadOnlyList<Element> elements)
{
foreach (Element ec in elements)
{
if (ec.HasChildren)
{
if (ec.StructElement.Type == "TR")
{
var cells = ec.Children.ToList().FindAll((e_) => e_.StructElement.Type == "TD").ToArray();
maxCols = Math.Max(maxCols, cells.Length);
List<IList<ITextParagraph>> tableCells = new List<IList<ITextParagraph>>();
foreach (var cell in cells)
tableCells.Add(cell.GetParagraphs());
table.Add(tableCells);
}
else
SelectRows(ec.Children);
}
}
}
SelectRows(e.Children);
// テーブルのページを取得します。
var sourcePage = FindPage(e.StructElement);
if (sourcePage == null)
throw new Exception("予期しないエラー:テーブルのデフォルトページが見つかりませんでした。");
var tl = new TextLayout(72);
// テキストレイアウトにテーブルデータを追加します。
tl.Append($"\n元のドキュメントの {sourcePage.Index + 1} ページ目のテーブルには、列が {maxCols} 列と、行が {table.Count} 行あります。\nデータは以下のとおりです:", _tfHdr);
tl.AppendParagraphBreak();
int irow = 0;
foreach (var row in table)
{
int icol = 0;
foreach (var cell in row)
{
foreach (var para in cell)
{
tl.Append(para.GetText());
}
if (row.IndexOf(cell) <= row.Count)
tl.Append("\t");
else
tl.AppendLine();
++icol;
}
++irow;
tl.AppendLine();
}
return (tl, sourcePage);
}
private Page FindPage(StructElement se)
{
if (se.DefaultPage != null)
return se.DefaultPage;
if (se.HasChildren)
foreach (var child in se.Children)
{
var p = FindPage(child);
if (p != null)
return p;
}
return null;
}
}
}