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

namespace DsPdfWeb.Demos
{
    // このサンプルでは、DsPdf の資料を使用して PDF を作成しています。
    // PDF レイヤー(オプションコンテンツ)は、複数の言語で記述された資料を
    // 同じ1ページの PDF にて提供するために使用されています。 対応するビューワ(Adobe Readerなど)を
    // 使用することで、異なる言語の表示/非表示を切り替えることができます。
    public class LangLayers
    {
        // レイヤ名は言語に対応するように設定します。
        const string c_lyrEN = "英語";
        const string c_lyrFR = "フランス語";
        const string c_lyrJP = "日本語";

        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();

            // 英語、フランス語、日本語のレイヤーを追加し、
            // フランス語及び日本語のレイヤーをデフォルトで非表示にします。
            doc.OptionalContent.AddLayer(c_lyrEN);
            doc.OptionalContent.AddLayer(c_lyrFR);
            doc.OptionalContent.SetLayerDefaultState(c_lyrFR, false);
            doc.OptionalContent.AddLayer(c_lyrJP);
            doc.OptionalContent.SetLayerDefaultState(c_lyrJP, false);

            var page = doc.Pages.Add();
            page.Landscape = true;
            var g = page.Graphics;

            // 背景画像
            var picBack = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "2020-website-gcdocs-headers_tall.png"));
            var rc = page.Bounds;
            rc.Height *= 0.5f;
            g.DrawImage(picBack, rc, null, ImageAlign.StretchImage);

            // スクリーンショットを含む画像
            var picScreens = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "docs-main-02.png"));
            var picScreensSize = new SizeF(picScreens.Width / 2, picScreens.Height / 2);
            var rcScreen = new RectangleF(
                page.Bounds.Width - picScreensSize.Width - 8,
                8,
                picScreensSize.Width,
                picScreensSize.Height);
            g.DrawImage(picScreens, rcScreen, null, ImageAlign.StretchImage);

            // テキストフォーマット
            var fReg = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "OpenSans-Regular.ttf"));
            var fBold = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "OpenSans-Bold.ttf"));
            var tfNorm = new TextFormat() { Font = fReg, FontSize = 9, ForeColor = Color.White };
            var tfCap = new TextFormat(tfNorm) { FontSize = tfNorm.FontSize * 1.6f };
            var tfBlack = new TextFormat(tfNorm) { ForeColor = Color.FromArgb(32, 32, 32) };
            var tfHdr = new TextFormat(tfBlack) { Font = fBold };

            // 英語のテキストを描画します。
            var ip = new PointF(36, 24);
            var ip1 = ip;
            ip = DrawText1(c_lyrEN, doc, g, ip1, tfNorm, tfCap);
            ip.Y += 82;
            var ip2 = ip;
            DrawText2(c_lyrEN, doc, g, ip2, tfHdr, tfBlack);

            // フランス語のテキストを描画します。
            DrawText1(c_lyrFR, doc, g, ip1, tfNorm, tfCap);
            DrawText2(c_lyrFR, doc, g, ip2, tfHdr, tfBlack);

            // 日本語のテキストを描画します。
            var fRegJp = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "YuGothR.ttc"));
            var fBoldJp = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "YuGothB.ttc"));
            DrawText1(c_lyrJP, doc, g, ip1, new TextFormat(tfNorm) { Font = fRegJp }, new TextFormat(tfCap) { Font = fRegJp });
            DrawText2(c_lyrJP, doc, g, ip2, new TextFormat(tfHdr) { Font = fBoldJp }, new TextFormat(tfBlack) { Font = fRegJp });

            // PDF を保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }

        class Texts
        {
            public string Caption { get; set; }
            public string SubCap { get; set; }
            public string Bullet1 { get; set; }
            public string Bullet2 { get; set; }
            public string Bullet3 { get; set; }
            public string Bullet4 { get; set; }
            public string Bullet5 { get; set; }
            public string Bullet6 { get; set; }
            public string Pt1Hdr { get; set; }
            public string Pt1Txt { get; set; }
            public string Pt2Hdr { get; set; }
            public string Pt2Txt { get; set; }
            public string Pt3Hdr { get; set; }
            public string Pt3Txt { get; set; }
            public string Pt4Hdr { get; set; }
            public string Pt4Txt { get; set; }
            public string Pt5Hdr { get; set; }
            public string Pt5Txt { get; set; }
            public string Pt6Hdr { get; set; }
            public string Pt6Txt { get; set; }
        }

        static Dictionary<string, Texts> _texts = new Dictionary<string, Texts>()
        {
            { "英語", new Texts() {
                Caption = "Fast, Efficient Document APIs for .NET 6 Applications",
                SubCap = "Take total control of your documents with ultra-fast, low-footprint APIs for enterprise apps.",
                Bullet1 = "Generate, load, edit, save XLSX spreadsheets, and PDF files using C# .NET, or VB.NET",
                Bullet2 = "View, edit, print, fill and submit documents in JavaScript PDF Viewer and PDF Editor",
                Bullet3 = "Fully compatible with Windows, macOS, and Linux",
                Bullet4 = "No dependencies on Excel, or Acrobat",
                Bullet5 = "Deploy to a variety of cloud-based services, including Azure, AWS, and AWS Lambda",
                Bullet6 = "Product available individually or as a bundle",
                Pt1Hdr = "High-Speed, Small Footprint, No Dependencies",
                Pt1Txt = "The .NET 6 Document API is designed to generate large, optimized documents fast – while remaining lightweight and extensible, giving you greater flexibility, and creativity in developing your applications.",
                Pt2Hdr = "Full .NET Support for Windows, Linux, and Mac",
                Pt2Txt = "Develop for any .NET platform or major operating system with a single code base. Use in your apps for .NET, C#, VB.NET .NET Framework, Mono, Xamarin.iOS, and Xamarin.Android.",
                Pt3Hdr = "Comprehensive, Highly Programmable",
                Pt3Txt = "Do more with your Excel spreadsheets, and PDF with our feature-rich APIs. Create, load, edit, save, and convert your business documents with intuitive tools.",
                Pt4Hdr = "Zero Dependencies",
                Pt4Txt = "Generate and edit digital documents in your applications without any dependencies on Adobe Acrobat, or Excel. Build your documents even faster with zero dependencies.",
                Pt5Hdr = "Deploy Apps to the Cloud",
                Pt5Txt = "Be everywhere with cloud-based deployment using NuGet and GrapeCity Documents. You can now deploy to Azure, AWS, and AWS Lambda in a few short steps.",
                Pt6Hdr = "Supports Hundreds of Features",
                Pt6Txt = "Generate full-featured documents and nearly lossless imports! These APIs complete your toolkit through high-performance features, including Excel pivot tables, and PDF digital signatures.",
            }},
            { "フランス語", new Texts() {
                Caption = "API de document rapides et efficaces pour les applications .NET 6",
                SubCap = "Prenez le contrôle total de vos documents avec des API ultra-rapides et à faible encombrement pour les applications d'entreprise.",
                Bullet1 = "Générez, chargez, modifiez et enregistrez des feuilles de calcul XLSX et des fichiers PDF à l'aide de C# .NET ou VB.NET",
                Bullet2 = "Affichez, modifiez, imprimez, remplissez et soumettez des documents dans JavaScript PDF Viewer et PDF Editor",
                Bullet3 = "Entièrement compatible avec Windows, macOS et Linux",
                Bullet4 = "Aucune dépendance à Excel ou Acrobat",
                Bullet5 = "Déploiement sur une variété de services basés sur le cloud, y compris Azure, AWS et AWS Lambda",
                Bullet6 = "Produit disponible individuellement ou en lot",
                Pt1Hdr = "Haut vitesse, faible encombrement, aucune dépendance",
                Pt1Txt = "L'API de document .NET 6 est conçue pour générer rapidement des documents volumineux et optimisés, tout en restant léger et extensible, vous offrant une plus grande flexibilité et créativité dans le développement de vos applications.",
                Pt2Hdr = "Support complète de .NET pour Windows, Linux et Mac",
                Pt2Txt = "Développez pour n'importe quelle plate-forme .NET ou système d'exploitation majeur avec une base de code unique. À utiliser dans vos applications pour .NET, C#, VB.NET .NET Framework, Mono, Xamarin.iOS et Xamarin.Android.",
                Pt3Hdr = "Complet, hautement programmable",
                Pt3Txt = "Faites-en plus avec vos feuilles de calcul Excel et vos PDF grâce à nos API riches en fonctionnalités. Créez, chargez, modifiez, enregistrez et convertissez vos documents commerciaux avec des outils intuitifs.",
                Pt4Hdr = "Zéro dépendances",
                Pt4Txt = "Générez et modifiez des documents numériques dans vos applications sans aucune dépendance à Adobe Acrobat ou Excel. Créez vos documents encore plus rapidement sans aucune dépendance.",
                Pt5Hdr = "Déployer des applications sur le cloud",
                Pt5Txt = "Soyez partout avec un déploiement basé sur le cloud à l'aide de NuGet et GrapeCity Documents. Vous pouvez désormais déployer sur Azure, AWS et AWS Lambda en quelques étapes courtes.",
                Pt6Hdr = "Prend en charge des centaines de fonctionnalités",
                Pt6Txt = "Générez des documents complets et des importations presque sans pertes! Ces API complètent votre boîte à outils grâce à des fonctionnalités hautes performances, notamment des tableaux croisés dynamiques Excel et des signatures numériques PDF.",
            }},
            { "日本語", new Texts() {
                Caption = ".NET 6 にて Excel や PDF を作成・編集できるドキュメント API",
                SubCap = "ドキュメントを作成・編集する API ライブラリです。Excel や PDF ファイルを C# および VB.NET のコードから API を利用して操作できます。",
                Bullet1 = "C# .NET または VB.NET を使用して、XLSX ファイルまたは PDF ファイルの生成、読み込み、編集、保存を行うことができます。",
                Bullet2 = "JavaScript ベースの PDF ビューワとその編集機能にて、PDF ドキュメントの閲覧、編集、印刷、記入、提出を行うことができます。",
                Bullet3 = "Windows、macOS、Linux に完全に対応しています。",
                Bullet4 = "Excel や Acrobat への依存はありません。",
                Bullet5 = "Azure、AWS、AWS Lambda など、さまざまなクラウドサービスにデプロイすることができます。",
                Bullet6 = "DioDocs for Excel と DioDocs for PDF の2製品があります。",
                Pt1Hdr = "外部依存のない高速かつ軽量なライブラリ",
                Pt1Txt = ".NET 6 で使用できるドキュメント API は、大規模かつ最適化されたドキュメントを高速に生成するように設計されているだけでなく、軽量で拡張性が高いため、アプリケーション開発においてより高い柔軟性と創造性を提供できます。",
                Pt2Hdr = "Windows、Linux、macOS の .NET に完全対応",
                Pt2Txt = "ひとつのコードベースで、すべての .NET プラットフォームや主要なオペレーティングシステム向けの開発を行うことができます。.NET C#、VB.NET、.NET Framework、Mono、Xamarin.iOS、Xamarin.Android 用のアプリケーションで使用できます。",
                Pt3Hdr = "機能性とプログラマビリティ",
                Pt3Txt = "豊富な機能を持つ API を利用して、Excel ファイルや PDF ドキュメントをさらに活用できます。直感的なツールで、ビジネス文書の作成、読み込み、編集、保存、変換が可能です。",
                Pt4Hdr = "外部への依存なし",
                Pt4Txt = "Adobe Acrobat、MS Excel に依存することなく、アプリケーションにてデジタル文書を生成、編集できます。依存性がないため、ドキュメントをより速く構築できます。",
                Pt5Hdr = "クラウドへのアプリのデプロイ",
                Pt5Txt = "Azure、AWS、AWS Lambda へのアプリケーションのデプロイを簡単に行うことができます。DioDocs パッケージの依存関係は、すべて NuGet で解決できます。",
                Pt6Hdr = "様々な機能をサポート",
                Pt6Txt = "Excel のピボットテーブルや PDF の電子署名などの高性能な機能を使用して、ドキュメントを生成し、ほぼ欠落なしで読み込むことができます。",
            }}
        };


        static PointF DrawText1(string lang, GcPdfDocument doc, GcPdfGraphics g, PointF ip, TextFormat tf, TextFormat tfCap)
        {
            var txts = _texts[lang];
            g.BeginLayer(lang);

            var tl = g.CreateTextLayout();
            tl.MaxWidth = 72 * 5;

            tl.AppendLine(txts.Caption, tfCap);
            tl.AppendLine(tf);
            tl.AppendLine(txts.SubCap, tf);
            tl.AppendLine(tf);
            g.DrawTextLayout(tl, ip);

            // 箇条書きのリスト
            ip.Y += tl.ContentHeight;
            tl.Clear();
            const string bullet = "\x2022\x2003";
            tl.FirstLineIndent = -g.MeasureString(bullet, tf).Width;
            tl.ParagraphSpacing += 4;

            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet1, tf);
            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet2, tf);
            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet3, tf);
            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet4, tf);
            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet5, tf);
            tl.Append(bullet, tf);
            tl.AppendLine(txts.Bullet6, tf);
            g.DrawTextLayout(tl, ip);

            g.EndLayer();

            ip.Y += tl.ContentHeight;
            return ip;
        }

        static void DrawText2(string lang, GcPdfDocument doc, GcPdfGraphics g, PointF ip, TextFormat tfHdr, TextFormat tfBlack)
        {
            var picIcons = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "2020-icon-sprites-dx.png"));
            var iconSize = new SizeF(picIcons.Width / 12, picIcons.Height / 2);

            var tl = g.CreateTextLayout();
            tl.FirstLineIndent = 0;
            tl.MaxWidth = (doc.Pages[0].Bounds.Width - ip.X * 2 - 36) / 3;
            var ip1 = ip;
            var txts = _texts[lang];

            drawItem(ip, 0, txts.Pt1Hdr, txts.Pt1Txt);
            ip.X += tl.MaxWidth.Value + 18;
            ip1.Y = Math.Max(ip1.Y, ip.Y + tl.ContentHeight);
            drawItem(ip, 1, txts.Pt2Hdr, txts.Pt2Txt);
            ip.X += tl.MaxWidth.Value + 18;
            ip1.Y = Math.Max(ip1.Y, ip.Y + tl.ContentHeight);
            drawItem(ip, 2, txts.Pt3Hdr, txts.Pt3Txt);

            ip1.Y = Math.Max(ip1.Y, ip.Y + tl.ContentHeight);
            ip1.Y += iconSize.Height + 18;
            ip = ip1;
            drawItem(ip, 3, txts.Pt4Hdr, txts.Pt4Txt);
            ip.X += tl.MaxWidth.Value + 18;
            drawItem(ip, 4, txts.Pt5Hdr, txts.Pt5Txt);
            ip.X += tl.MaxWidth.Value + 18;
            drawItem(ip, 5, txts.Pt6Hdr, txts.Pt6Txt);

            void drawItem(PointF p, int imgIdx, string header, string text)
            {
                if (lang == c_lyrEN)
                {
                    // アイコンを一度だけ描画します。
                    var xImg = p.X + tl.MaxWidth.Value / 2 - iconSize.Width / 2;
                    var xImgAll = xImg - imgIdx * iconSize.Width;
                    var imgRc = new RectangleF(
                        xImgAll,
                        p.Y,
                        iconSize.Width * 6,
                        iconSize.Height);
                    var rcClip = new RectangleF(new PointF(xImg, p.Y), iconSize);
                    rcClip.Width -= 1;
                    g.DrawImage(picIcons, imgRc, rcClip, ImageAlign.StretchImage);
                }
                tl.Clear();
                tl.AppendLine(header, tfHdr);
                tl.AppendLine(text, tfBlack);
                g.BeginLayer(lang);
                g.DrawTextLayout(tl, new PointF(p.X, p.Y + iconSize.Height + 8));
                g.EndLayer();
            }
        }
    }
}