ElixirでPDFファイルを生成しPhoenixで静的ファイルとしてホスティングする


関わっている案件でElixir+Phoenixで組んでるバックエンドサーバーでPDFを作成してWeb表示する要件が出てきたので、やってみました。

試したのは以下のライブラリ

https://github.com/gutschilla/elixir-pdf-generator

wkhtmltopdfというライブラリのWrapperということ
使用方法は超簡単だった。

# 手順

## wkhtmltopdfをインストールする

以下の公式サイトからOSに合わせたインストーラを使用する。

https://wkhtmltopdf.org/downloads.html

筆者はMacで実施

## プロジェクトの作成

```
> mix phx.new pdf_sample --no-ecto --no-brunch
```

## depsの追加

```elixir:mix.exs
  def application do
    [
      mod: {PdfSample.Application, []},
      extra_applications: [:logger, :runtime_tools, :pdf_generator] #<-　:pdf_generator追加
    ]
  end
  defp deps do
    [
      {:phoenix, "~> 1.3.2"},
      {:phoenix_pubsub, "~> 1.0"},
      {:phoenix_html, "~> 2.10"},
      {:phoenix_live_reload, "~> 1.0", only: :dev},
      {:gettext, "~> 0.11"},
      {:cowboy, "~> 1.0"},
      {:pdf_generator, ">=0.3.7" }, #<-　追加
    ]
  end
```

```
> mix .deps.get
```

## コード本体

今回は試すだけだったので、モジュールを作らずにiexで実行した。

```elixir
iex(1)> source_html = "<html><body><p>Hi there!</p></body></html>"
# ページサイズA5とファイル名を任意指定
iex(2)> { :ok, filename } = PdfGenerator.generate source_html, page_size: "A5", 
 filepath: "/Users/tsuchiro/code/samples/pdf_sample/priv/static/pdf", filename: "sample_pdf"
# 結果は作成されたファイルのフルパスがタプルで返ってくる
iex(3)> {:ok, pdf_path} = {:ok, "/var/folders/pz/2847mdrn0gz51b2tctnfqc740000gn/T/sample_pdf.pdf"}
# 静的ファイルのパスにコピーする
iex(4)> File.copy(pdf_path,"./priv/static/pdf/sample_pdf.pdf")
```　

## 画面にリンクを追加

```html:/pdf_sample_web/templates/page/index.html.eex

<div class="jumbotron">
  <h2><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h2>
  <p class="lead">A productive web framework that<br />does not compromise speed and maintainability.</p>
</div>

<div class="row marketing">
  <div class="col-lg-6">
    <h4>Resources</h4>
    <ul>
      <li>
        <a href="http://phoenixframework.org/docs/overview">Guides</a>
      </li>
      <li>
        <a href="https://hexdocs.pm/phoenix">Docs</a>
      </li>
      <li>
        <a href="https://github.com/phoenixframework/phoenix">Source</a>
      </li>
       <li>
       <!--  ↓ PDFファイルへのリンクを追加  -->
        <a href="<%= static_path(@conn, "/pdf/sample_pdf.pdf") %>">PDF Document</a>
      </li>
    </ul>
  </div>

  <div class="col-lg-6">
    <h4>Help</h4>
    <ul>
      <li>
        <a href="http://groups.google.com/group/phoenix-talk">Mailing list</a>
      </li>
      <li>
        <a href="http://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on freenode IRC</a>
      </li>
      <li>
        <a href="https://twitter.com/elixirphoenix">@elixirphoenix</a>
      </li>
    </ul>
  </div>
</div>

```


## エンドポイントにcssを追加する。

static_pathはpriv/static以下を指すが、デフォルトではアクセスできるパスに制限が掛かっているので、pdfフォルダを追加する。

```
  plug Plug.Static,
    at: "/", from: :pdf_sample, gzip: false,
    only: ~w(css fonts images js pdf favicon.ico robots.txt) # <- pdfを追加
```

# アクセスしてみる

http://0.0.0.0:4000/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/243163/15f9f24a-e4f6-47c1-8114-ccd39ceb2e74.png)

http://0.0.0.0:4000/pdf/sample_pdf.pdf

![image.png](https://qiita-image-store.s3.amazonaws.com/0/243163/a7f71b82-bd3d-4a63-45a8-fcb0d8a9e005.png)

簡単にできました。

WebKitでHTMLを描画してPDFにしているようなので、元のHTMLさえ作り込めば凝ったPDFも作れそうですね。