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

namespace DsPdfWeb.Demos
{
    // このサンプルは、いくつかのバーコードを含む出荷ラベルのセットを印刷します。
    // タブストップを使用してデータを垂直に整列させることにも注意してください。
    public class ShippingLabels
    {
        // クライアント情報です。このサンプルは、クライアントごとに1つの出荷ラベルを印刷します。
        class Client
        {
            public string Name;
            public string Addr;
            public string City;
            public string Country;
            public Client(string name, string addr, string city, string country)
            {
                Name = name;
                Addr = addr;
                City = city;
                Country = country;
            }
        }

        // クライアントのベース。
        static readonly List<Client> s_clients = new List<Client>()
        {
            new Client("Simons bistro", "Vinbćltet 34", "Křbenhavn", "Denmark"),
            new Client("Richter Supermarkt", "Starenweg 5", "Genčve", "Switzerland"),
            new Client("Bon app'", "12, rue des Bouchers", "Marseille", "France"),
            new Client("Rattlesnake Canyon Grocery", "2817 Milton Dr.", "Albuquerque", "USA"),
            new Client("Lehmanns Marktstand", "Magazinweg 7", "Frankfurt a.M.", "Germany"),
            new Client("LILA-Supermercado", "Carrera 52 con Ave. Bolívar #65-98 Llano Largo", "Barquisimeto", "Venezuela"),
            new Client("Ernst Handel", "Kirchgasse 6", "Graz", "Austria"),
            new Client("Pericles Comidas clásicas", "Calle Dr. Jorge Cash 321", "México D.F.", "Mexico"),
            new Client("Drachenblut Delikatessen", "Walserweg 21", "Aachen", "Germany"),
            new Client("Queen Cozinha", "Alameda dos Canŕrios, 891", "Săo Paulo", "Brazil"),
            new Client("Tortuga Restaurante", "Avda. Azteca 123", "México D.F.", "Mexico"),
            new Client("Save-a-lot Markets", "187 Suffolk Ln.", "Boise", "USA"),
            new Client("Franchi S.p.A.", "Via Monte Bianco 34", "Torino", "Italy"),
            // new Client("", "", "", ""),
        };

        // メインのサンプルドライバーです。
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            Init(doc);

            // クライアントをループし、1ページに4つのラベルを印刷します。
            int i = 0;
            for (int pg = 0; pg < (s_clients.Count + 3) / 4; ++pg)
            {
                Page page = doc.NewPage();
                PrintLabel(s_clients[i++], page, new RectangleF(hmargin, vmargin, _labelWidth, _labelHeight));
                if (i < s_clients.Count)
                    PrintLabel(s_clients[i++], page, new RectangleF(hmargin + _labelWidth, vmargin, _labelWidth, _labelHeight));
                if (i < s_clients.Count)
                    PrintLabel(s_clients[i++], page, new RectangleF(hmargin, vmargin + _labelHeight, _labelWidth, _labelHeight));
                if (i < s_clients.Count)
                    PrintLabel(s_clients[i++], page, new RectangleF(hmargin + _labelWidth, vmargin + _labelHeight, _labelWidth, _labelHeight));
            }
            // PDF ドキュメントを保存します。
            doc.Save(stream);
            Term();
            return doc.Pages.Count;
        }

        // ラベルを描画するために使用されるコンストラクタおよび変数です。
        const float hmargin = 24, vmargin = 36;
        float _labelWidth, _labelHeight;
        GCDRAW.Pen _pBold, _pNorm;
        GCTEXT.Font _fontReg, _fontBold;
        TextFormat _tfSmall, _tfSmallB, _tfLarge;
        List<TabStop> _tsHeader, _tsFrom, _tsCodes;
        GCDRAW.Image _logo;
        ImageAlign _ia;
        GcBarcode bcTop, bcBottom;

        // ラベルの描画に使用される変数を初期化します。
        void Init(GcPdfDocument doc)
        {
            _labelWidth = (doc.PageSize.Width - hmargin * 2) / 2;
            _labelHeight = _labelWidth;
            _pBold = new GCDRAW.Pen(Color.Black, 2);
            _pNorm = new GCDRAW.Pen(Color.Black, 0.5f);
            _logo = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "AcmeLogo-vertical-250px.png"));
            _fontReg = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeui.ttf"));
            _fontBold = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "segoeuib.ttf"));
            _tfSmall = new TextFormat() { Font = _fontReg, FontSize = 8 };
            _tfSmallB = new TextFormat() { Font = _fontBold, FontSize = 8 };
            _tfLarge = new TextFormat() { Font = _fontBold, FontSize = 14 };

            _ia = new ImageAlign(ImageAlignHorz.Right, ImageAlignVert.Center, true, true, true, false, false);
            _tsHeader = new List<TabStop>() { new TabStop(24, TabStopAlignment.Leading), new TabStop(108, TabStopAlignment.Leading) };
            _tsFrom = new List<TabStop>() { new TabStop(12, TabStopAlignment.Leading), new TabStop(72, TabStopAlignment.Leading) };
            _tsCodes = new List<TabStop>() { new TabStop(_labelWidth / 8, TabStopAlignment.Center) };

            bcTop = new GcBarcode() {
                TextFormat = _tfSmall,
                CodeType = CodeType.Code_128_B,
                HorizontalAlignment = ImageAlignHorz.Center,
                VerticalAlignment = ImageAlignVert.Center,
            };
            bcTop.Options.CaptionPosition = BarCodeCaptionPosition.Below;
            bcBottom = new GcBarcode()
            {
                TextFormat = _tfSmall,
                CodeType = CodeType.Code_128auto,
                HorizontalAlignment = ImageAlignHorz.Center,
                VerticalAlignment = ImageAlignVert.Center,
            };
            bcBottom.Options.CaptionPosition = BarCodeCaptionPosition.Below;
        }

        void Term()
        {
            _logo?.Dispose();
            _logo = null;
        }

        void PrintLabel(Client client, Page page, RectangleF bounds)
        {
            // いくつかのサンプルデータをランダム化するために使用します。
            var rnd = Common.Util.NewRandom();

            // サンプルの荷送人/送付先データです。
            var shipper = rnd.Next(2) == 0 ? "United Package" : "Speedy Express";
            (string name, string addr, string city, string country, string zip) sender =
                (name: "ACME Inc.", addr: "1 Main Street", city: "Metropolis", country: "USA", zip: "34567");
            var shuttle = rnd.Next(10000, 15000).ToString();
            var area = rnd.Next(1, 12).ToString();
            var tour = rnd.Next(0, 20).ToString();

            var g = page.Graphics;

            var tl = g.CreateTextLayout();
            tl.DefaultFormat.Font = _tfSmall.Font;
            tl.DefaultFormat.FontSize = _tfSmall.FontSize;
            tl.LineSpacingScaleFactor = 0.75f;
            tl.ParagraphAlignment = ParagraphAlignment.Center;

            // ヘッダー。
            var hHeader = bounds.Height / 2 / 5;
            var rHeader = new RectangleF(bounds.X, bounds.Y, bounds.Width, hHeader);
            tl.TabStops = _tsHeader;
            tl.Append($"\t{shipper}");
            tl.Append("\tCMR", _tfSmallB);
            tl.Append($"\n\t\t{Common.Util.TimeNow():yyyy-MM-dd}");
            tl.MaxHeight = rHeader.Height;
            tl.MaxWidth = rHeader.Width;
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, rHeader.Location);

            var rLogo = rHeader;
            rLogo.Inflate(-5, -5);
            g.DrawImage(_logo, rLogo,  null, _ia);

            // 差出人。
            var hFrom = hHeader;
            var rFrom = new RectangleF(bounds.X, rHeader.Bottom, bounds.Width, hFrom);
            tl.Clear();
            tl.TabStops = _tsFrom;
            tl.Append($"\tFrom:\t{sender.name}\n\t\t{sender.addr}\n\t\t{sender.city}, {sender.country} {sender.zip}");
            tl.MaxHeight = rFrom.Height;
            tl.MaxWidth = rFrom.Width;
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, rFrom.Location);

            // 宛先。
            var hTo = bounds.Height / 2 / 3;
            var rTo = new RectangleF(bounds.X, rFrom.Bottom, bounds.Width, hTo);
            tl.Clear();
            tl.TabStops = _tsFrom;
            tl.Append($"\tTo:\t{client.Name}\n\t\t{client.Addr}\n\t\t{client.City}\n\t\t{client.Country}");
            tl.MaxHeight = rTo.Height;
            tl.MaxWidth = rTo.Width;
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, rTo.Location);

            // コード。
            var hCodes = bounds.Height / 2 / (15f / 4);
            var rCodes = new RectangleF(bounds.X, rTo.Bottom, bounds.Width, hCodes);
            tl.TabStops = _tsCodes;
            tl.Clear();
            tl.AppendLine("\tShuttle");
            tl.Append($"\t{shuttle}", _tfLarge);
            tl.MaxHeight = rCodes.Height;
            tl.MaxWidth = rCodes.Width / 4;
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, rCodes.Location);

            tl.Clear();
            tl.AppendLine("\tArea");
            tl.Append($"\t{area}", _tfLarge);
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, new PointF(rCodes.X + rCodes.Width / 4, rCodes.Y));

            tl.Clear();
            tl.AppendLine("\tException");
            tl.Append("\t ", _tfLarge);
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, new PointF(rCodes.X + rCodes.Width / 4 * 2, rCodes.Y));

            tl.Clear();
            tl.AppendLine("\tTour");
            tl.Append($"\t{tour}", _tfLarge);
            tl.PerformLayout(true);
            g.DrawTextLayout(tl, new PointF(rCodes.X + rCodes.Width / 4 * 3, rCodes.Y));

            // バーコード。
            var hBarcodes = bounds.Height / 2;
            var rBcTop = new RectangleF(bounds.X, rCodes.Bottom, bounds.Width, hBarcodes / 2);
            var rBcBottom = new RectangleF(bounds.X, rBcTop.Bottom, bounds.Width, hBarcodes / 2);

            bcTop.Text = client.Country;
            g.DrawBarcode(bcTop, rBcTop);

            // 長めの「コード」を作成します。
            var code = $"{client.Name[0]}{client.Addr[0]}{client.City[0]}{client.Country[0]}".ToUpper();
            bcBottom.Text = $"{code}{client.GetHashCode().ToString("X12")}";
            g.DrawBarcode(bcBottom, rBcBottom);

            // 線。
            g.DrawLine(rHeader.Left, rHeader.Bottom, rHeader.Right, rHeader.Bottom, _pNorm);
            g.DrawLine(rFrom.Left, rFrom.Bottom, rFrom.Right, rFrom.Bottom, _pNorm);
            g.DrawLine(rTo.Left, rTo.Bottom, rTo.Right, rTo.Bottom, _pNorm);
            g.DrawLine(rCodes.Left, rCodes.Bottom, rCodes.Right, rCodes.Bottom, _pNorm);

            g.DrawLine(rCodes.Left + rCodes.Width / 4, rCodes.Top, rCodes.Left + rCodes.Width / 4, rCodes.Bottom, _pNorm);
            g.DrawLine(rCodes.Left + rCodes.Width / 4 * 2, rCodes.Top, rCodes.Left + rCodes.Width / 4 * 2, rCodes.Bottom, _pNorm);
            g.DrawLine(rCodes.Left + rCodes.Width / 4 * 3, rCodes.Top, rCodes.Left + rCodes.Width / 4 * 3, rCodes.Bottom, _pNorm);

            g.DrawRectangle(bounds, _pBold);
        }
    }
}