[C#]iTextSharpでtemplateに文字を乗せてPDF出力する。

C#

前回に引き続き、iTextSharpですが、PDFテンプレートを作っておいて出力したい時があると思います。
メソッド引数が変わって、ちょっとハマったところがあったので、書いてみたいと思います。

PDFテンプレートを配置する

pdfをプロジェクト配下の適当な位置に配置します。
今回もプロジェクトから使うので、右クリックして常にコピーにしておきます。

ソース

functionのところを載せてます!詳細はgithubを見てください。

[FunctionName("TestPdfOutputOverwrite")]
public HttpResponseMessage TestPdfOutputOverwrite(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = "test_output_pdf")] HttpRequest req,
    ILogger log
)
{
    EncodingProvider encodingProvider;
    encodingProvider = CodePagesEncodingProvider.Instance;
    Encoding.RegisterProvider(encodingProvider);

    // 取得したPDFのサイズでDocument作成
    var reader = new PdfReader(@"Google.pdf");
    var doc = new Document(reader.GetPageSize(1));
    var ms = new MemoryStream();

    //ファイルの出力先を設定
    var pw = PdfWriter.GetInstance(doc, ms);

    //ドキュメントを開く
    doc.Open();

    var pdfContentByte = pw.DirectContent;

    // テンプレートのページを追加する
    doc.NewPage();
    var page = pw.GetImportedPage(reader, 1);
    pdfContentByte.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);

    var bf = BaseFont.CreateFont(@"MS Gothic.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

    // ベースフォントとフォントサイズを指定する。
    pdfContentByte.SetFontAndSize(bf, 10);

    // 指定箇所に文字列を記述
    ShowTextAligned(pdfContentByte, 10, 500, "Googleのページやで!");
    ShowTextAligned(pdfContentByte, 10, 480, "日本語の出力テスト。");
    DrawLine(pdfContentByte, 2, 451, 840, 451);

    doc.Close();

    // レスポンス作成
    var response = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(ms.GetBuffer())
    };

    //Content-Dispositionをattachmentでファイル名を指定していたらプレビューが開かない
    //response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    //{
    //    FileName = "testhoge.pdf"
    //};

    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");

    return response;

}

説明

PDFをテンプレートにするときに注意する点ですが、下記のようにPdfReaderで対象ファイルを読み込んで、

var reader = new PdfReader(@"Google.pdf");

PdfContentByteにページとして追加します。これを編集して行って、最後に出力しています。

doc.NewPage();
var page = pw.GetImportedPage(reader, 1);
pdfContentByte.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);

後はほとんど前回と同じですね。
AddTemplateのパラメータの数が分からなかったので、ハマりました。調べても三つだけのやつが多い😖
バージョンが新しくなったんでしょうねー。

動作確認

chormeでこんな感じのPDFを作成しました。

下記のように作成したPDFを読み込んで、文字を乗せることができました!


Azureでリソースがなくて動かない

ローカルで動かすとしっかり動作しましたが、
Azure上でfunctionを動かすと、pdfとフォントがない旨のエラーが出て動作しませんでした。
githubのソースは変更しています。

下記のように修正するとAzureでも動くようになります。

pdfとfontのリソースを右クリックして、埋め込みリソースにします。(embedded resourceを選択)
下記のようにテンプレートとフォントを取得します。

// リソース取得
Assembly assembly = Assembly.GetExecutingAssembly();            
Stream pdfStream = assembly.GetManifestResourceStream("iTextSharpFunction.Google.pdf");
Stream fontStream = assembly.GetManifestResourceStream("iTextSharpFunction.MS Gothic.ttf");

ストリームをPdfReaderに渡して使います。

var reader = new PdfReader(pdfStream);

CreateFontは引数を増やして、下記のようにすると渡せました。

var bf = BaseFont.CreateFont(@"MS Gothic.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, GetStreamToBytes(fontStream), null);

streamからbyte配列に変えないと、メソッドに渡せなかったので下記のようなprivateメソッドを用意しました。

private static byte[] GetStreamToBytes(Stream input)
{
    byte[] buffer = new byte[input.Length * 2];
    var ms = new MemoryStream();
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        ms.Write(buffer, 0, read);
    }
    return ms.ToArray();
}

githubにソースを…

今回も置いてます!(同じプロジェクトでfunctionを分けてます。)

コメント

タイトルとURLをコピーしました