読者です 読者をやめる 読者になる 読者になる

IT業界のすみっこ暮らし

ふと気がついたときの記録

iTextSharpを使ったPDF作成

.NET環境でPDF出力をする場面があったので自分用まとめ。

基本的にPDF作成は各要素をテーブルにして作成した方が調整するときにやり易い。

using iTextSharp.text;
using iTextSharp.text.pdf;

/// <summary>
/// PDFファイルを作成
/// ※1、フォーマット用のPDFファイルがある場合
/// ※2、複数枚のPDFを連続に出力する場合も対応可能
/// ※3、ウェブ・バッチ両方から呼ばれる場合を想定(共通ロジック)
/// </summary>
/// <param name="pdfStream">PDFストリーム</param>
/// <param name="resPdfModelList">PDF作成用のモデル(リスト)</param>
/// <param name="isCallFromBatch">ウェブ/バッチ両方から呼ばれる場合の判定用</param>
public void MakePdfStream(MemoryStream pdfStream, List<ResPdfModel> resPdfModelList, bool isCallFromBatch)
{
    var currenAppDatatPath = string.Empty;

    if (isCallFromBatch)
    {
        currenAppDatatPath = AppDomain.CurrentDomain.BaseDirectory + "App_Data";
    }
    else
    {
        currenAppDatatPath = HttpContext.Current.Request.PhysicalApplicationPath + "App_Data";
    }

    // Documentオブジェクト作成
    var document = new Document();
    var writer = PdfWriter.GetInstance(document, pdfStream);

    // フォントの準備
    FontFactory.RegisterDirectories();
    // フォント設定
    var baseFont = FontFactory.GetFont("MS Gothic", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, 8f);

    // 初期数値
    var paddingDefaultValue = 4f;
    var BorderDefaultValue = 0f;
    var leadingDefaultValue = 11f;

    // フォーマット情報を取得
    string pdfFormatPath = string.Empty;
    PdfReader reader = null;
    int formatPageCount = 0;
    PdfImportedPage page1 = null;
    PdfImportedPage page2 = null;
    PdfImportedPage page3 = null;
    bool uniqueFormat = false;

    if (resPdfModelList.Count == 1 || resPdfModelList.Count == resPdfModelList.Count(x => x.FormatPath == resPdfModelList[0].FormatPath))
    {
        // 全てのデータのフォーマットの値が同じの場合、foreachの前にPdfReaderを作成する。
        // もしフォーマットの値が異なる場合はforeachの中で行う。
        reader = new PdfReader(currenAppDatatPath + resPdfModelList[0].FormatPath);
        formatPageCount = reader.NumberOfPages;
        page1 = writer.GetImportedPage(reader, 1);
        page2 = writer.GetImportedPage(reader, 2);
        if (formatPageCount > 2)
        {
            page3 = writer.GetImportedPage(reader, 3);
        }
        uniqueFormat = true;
    }

    // 1P目
    document.Open();
    var pdfContentByte = writer.DirectContent;
    var listCount = 0;
    var count = 1;
    var tableBaseFont = baseFont;
    var cell = new PdfPCell(new Phrase(string.Empty, baseFont));

    var fixedHeightDefaultValueFor1page = 16.7f;
    var fixedHeightDefaultValue = 21f;
    var xPosDefaultValue = 119f;
    var tableWidthDefaultValue = 434f;

    foreach (var resPdfModel in resPdfModelList)
    {
        // 全てのデータのフォーマットが同じじゃない場合、その都度フォーマットを読み取る
        if (!uniqueFormat)
        {
            reader = new PdfReader(resPdfModel.FormatPath);
            formatPageCount = reader.NumberOfPages;
            page1 = writer.GetImportedPage(reader, 1);
            page2 = writer.GetImportedPage(reader, 2);
            if (formatPageCount > 2)
            {
                page3 = writer.GetImportedPage(reader, 3);
            }
        }

        if (listCount != 0)
        {
            document.NewPage();
        }

        // 背景にテンプレートを設定
        pdfContentByte.AddTemplate(page1, 0f, 0f);

        pdfContentByte.BeginText();
        pdfContentByte.SetFontAndSize(baseFont.BaseFont, 8);
        pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, resPdfModel.AccountIDForHeader, 515f, 800f, 0);
        pdfContentByte.EndText();

        #region #### サンプル「内容」 ####
        var infoTableWidths = new float[] { 0.41f, 0.165f, 0.425f };
        var infoTable = new PdfPTable(3);
        infoTable.SetWidths(infoTableWidths);
        infoTable.TotalWidth = tableWidthDefaultValue;

        var infoTableData = new List<string>();
        infoTableData.Add(resPdfModel.AccountID);
        infoTableData.Add("");
        infoTableData.Add(resPdfModel.RegisteredPhoneNumber);
        infoTableData.Add(resPdfModel.ContractName);
        infoTableData.Add("");
        infoTableData.Add(resPdfModel.PaymentMethod);

        count = 1;
        foreach (string title in infoTableData)
        {
            cell = new PdfPCell(new Phrase(GetChunk(title, tableBaseFont)));
            cell.BorderWidth = BorderDefaultValue;
            cell.BorderColor = new BaseColor(255, 153, 255);
            cell.FixedHeight = fixedHeightDefaultValueFor1page;
            cell.VerticalAlignment = Element.ALIGN_MIDDLE;
            cell.PaddingLeft = paddingDefaultValue;
            infoTable.AddCell(cell);
            count++;
        }
        infoTable.WriteSelectedRows(0, 10, xPosDefaultValue, 754f, pdfContentByte);
        #endregion

        // ==== 以下、1pの内容を記述 ====

        // 2P目
        document.NewPage();
        pdfContentByte.AddTemplate(page2, 0f, 0f);

        pdfContentByte.BeginText();
        pdfContentByte.SetFontAndSize(baseFont.BaseFont, 8);
        pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, resPdfModel.AccountIDForHeader, 525f, 812f, 0);
        pdfContentByte.EndText();

        // ==== 以下、2pの内容を記述 ====

        listCount++;
    }
    document.Close();
    reader.Close();
}

/// <summary>
/// 文字間隔の設定用
/// </summary>
/// <param name="text"></param>
/// <param name="font"></param>
/// <returns></returns>
private Chunk GetChunk(string text, Font font)
{
    Chunk chunk = new Chunk(text, font);
    chunk.SetCharacterSpacing(-0.6f);
    return chunk;
}