PdfA.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
// 
using System;
using System.IO;
using System.Drawing;
using System.Text;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Common;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Structure;
using GrapeCity.Documents.Pdf.MarkedContent;
using GrapeCity.Documents.Pdf.Graphics;
using GrapeCity.Documents.Pdf.Annotations;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos.Basics
{
    // このサンプルは、PDF/A-3u に準拠したドキュメントを作成する方法を示します。
    public class PdfA
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var date = new DateTime(1961, 4, 12, 6, 7, 0, DateTimeKind.Utc);

            // ドキュメントを PDF/A-3u 準拠としてマークします。
            doc.ConformanceLevel = PdfAConformanceLevel.PdfA3u;

            var fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "arial.ttf"));
            var gap = 36;

            // PDF/A-3a では、すべてのコンテンツにタグを付ける必要があるため、描画時に StructElement を作成してデータを入力します。
            var sePart = new StructElement("Part");
            doc.StructTreeRoot.Children.Add(sePart);

            TextLayout tl = null;
            // PDF/A 規格に従ってタグ付けされたサンプルコンテンツを持つ3つのページを追加します。
            for (int pageNo = 1; pageNo <= 3; ++pageNo)
            {
                // ページを追加します。
                var page = doc.Pages.Add();
                var g = page.Graphics;
                float y = 72;
                if (doc.Pages.Count == 1)
                {
                    // 段落要素を作成します。
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Part 要素に追加します。
                    sePart.Children.Add(seParagraph);

                    tl = g.CreateTextLayout();
                    tl.MarginAll = 72;
                    tl.MaxWidth = page.Size.Width;

                    tl.DefaultFormat.Font = fnt;
                    tl.DefaultFormat.FontBold = true;
                    tl.DefaultFormat.FontSize = 20;
                    tl.Append("PDF/A-3A ドキュメント");

                    // PerformLayout は、新規 TextLayout 内あるいは Clear() メソッドの呼び出し後に自動的に実行されます。
                    // tl.PerformLayout(true);

                    // タグ付けされたコンテンツ内に TextLayout を描画します。
                    g.BeginMarkedContent(new TagMcid("P", 0));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y = tl.ContentRectangle.Bottom + gap;

                    seParagraph.ContentItems.Add(new McidContentItemLink(0));
                }

                // PDF/A 規格に従ってタグ付けされたいくつかのサンプル段落を追加します。
                for (int i = 1; i <= 3; ++i)
                {
                    // 段落要素を作成します。
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Part 要素に追加します。
                    sePart.Children.Add(seParagraph);

                    var sb = new StringBuilder();
                    sb.Append(string.Format("ページ {1} 上の段落 {0}: ", i, pageNo));
                    sb.Append(Environment.NewLine);
                    sb.Append(Common.Util.getString_ja(0, 1, 2, 3, 6));
                    var para = sb.ToString();

                    tl.Clear();
                    tl.DefaultFormat.FontSize = 14;
                    tl.DefaultFormat.FontBold = false;
                    tl.MarginTop = y;
                    tl.Append(para);

                    // タグ付けされたコンテンツ内に TextLayout を描画します。
                    g.BeginMarkedContent(new TagMcid("P", i));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y += tl.ContentHeight + gap;

                    // 段落の StructElement にコンテンツ項目を追加します。
                    seParagraph.ContentItems.Add(new McidContentItemLink(i));

                    // PDF/A-3 ではファイルをドキュメントに埋め込むことができますが、いずれかのドキュメント要素に関連付ける必要があります。
                    // seParagraph に関連付けられた埋め込みファイルを追加します。
                    var ef1 = EmbeddedFileStream.FromBytes(doc, Encoding.UTF8.GetBytes(para));
                    // PDF/A の場合は、ModificationDate と MimeType を指定する必要があります。
                    ef1.ModificationDate = date;
                    ef1.MimeType = "text/plain";
                    var fn = string.Format("ページ{0}_段落{1}.txt", pageNo, i);
                    var fs1 = FileSpecification.FromEmbeddedStream(fn, ef1);
                    // UnicodeFile.FileName  はPDF/A 準拠のために指定する必要があります:
                    fs1.UnicodeFile.FileName = fs1.File.FileName;
                    // PDF/A の場合は、Relationship を指定する必要があります。
                    fs1.Relationship = AFRelationship.Unspecified;
                    doc.EmbeddedFiles.Add(fn, fs1);
                    seParagraph.AssociatedFiles.Add(fs1);
                }
            }

            // PDF/A-3 では、PDF ファイルに透過描画を行うことができます。いくつか追加します。
            var gpage = doc.Pages[0].Graphics;
            gpage.FillRectangle(new RectangleF(20, 20, 200, 200), Color.FromArgb(40, Color.Red));

            // PDF/A-3 では、FormXObjects を使用できます。透過したものを追加します。
            var r = new RectangleF(0, 0, 144, 72);
            var fxo = new FormXObject(doc, r);
            var gfxo = fxo.Graphics;
            gfxo.FillRectangle(r, Color.FromArgb(40, Color.Violet));
            var tf = new TextFormat()
            {
                Font = fnt,
                FontSize = 16,
                ForeColor = Color.FromArgb(100, Color.Black),
            };
            gfxo.DrawString("FormXObject", tf, r, TextAlignment.Center, ParagraphAlignment.Center);
            gfxo.DrawRectangle(r, Color.Blue, 3);
            gpage.DrawForm(fxo, new RectangleF(300, 250, r.Width, r.Height), null, ImageAlign.ScaleImage);

            // PDF/A-3 ではファイルをドキュメントに埋め込むことができますが、いずれかのドキュメント要素に関連付ける必要があります。
            var ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "WordDocs", "ProcurementLetter.docx"));
            // PDF/A の場合は、EmbeddedFile に対して ModificationDate と MimeType を指定する必要があります。
            ef.ModificationDate = date;
            ef.MimeType = "application/msword";
            var fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("ProcurementLetter.docx", fs);
            // 埋め込みファイルをドキュメントに関連付けます。
            doc.AssociatedFiles.Add(fs);

            // 注釈に関連付けられた添付ファイルを追加します。
            var sa = new StampAnnotation()
            {
                UserName = "Minerva",
                Font = fnt,
                Rect = new RectangleF(300, 36, 220, 72),
            };
            sa.Flags |= AnnotationFlags.Print;
            // スタンプ注釈を表す FormXObject を使用します。
            var stampFxo = new FormXObject(doc, new RectangleF(PointF.Empty, sa.Rect.Size));
            var gstampFxo = stampFxo.Graphics;
            gstampFxo.FillRectangle(stampFxo.Bounds, Color.FromArgb(40, Color.Green));
            gstampFxo.DrawString("minerva.jpg に関連する\nスタンプ注釈", tf, stampFxo.Bounds, TextAlignment.Center, ParagraphAlignment.Center);
            gstampFxo.DrawRectangle(stampFxo.Bounds, Color.Green, 3);
            //
            sa.AppearanceStreams.Normal.Default = stampFxo;
            doc.Pages[0].Annotations.Add(sa);
            ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "Images", "minerva.jpg"));
            ef.ModificationDate = date;
            ef.MimeType = "image/jpeg";
            fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("minerva.jpg", fs);
            sa.AssociatedFiles.Add(fs);

            // タグ付き PDF の規則に準拠しているとしてドキュメントにマークします(PDF/A の場合は必須です)。
            doc.MarkInfo.Marked = true;

            // PDF/A ドキュメントの場合、Metadata.CreatorTool と DocumentInfo.Creator は同じである必要があります。
            doc.Metadata.CreatorTool = doc.DocumentInfo.Creator;
            // PDF/A ドキュメントにはタイトルを指定する必要があります。
            doc.Metadata.Title = "DsPdf ドキュメント";
            doc.ViewerPreferences.DisplayDocTitle = true;

            // PDF ドキュメントを保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}