エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

海老で PDF を釣る

単票を作るために、Ruby で PDF を生成するライブラリ Prawn を試してみました。


以下、Prawn を使って PDF ができるまでの様子です。

Prawn を導入する

RubyGem で提供されているので、それインストールします。

$ gem install prawn


PDF ファイルを作成してみます。

require 'prawn'

Prawn::Document.generate('sample.pdf', page_size: 'A4') do |pdf|
  pdf.text 'Hello, Prawn!'
end

これで sample.pdf というファイル名の A4 サイズの PDF ファイルが作成されます。


直接ファイルを生成するのではなく、レンダリングしたデータを生成することもできます。
次の例では、Prawn::Document#renderレンダリングしたデータを IO.write でファイルに保存しています。

require 'prawn'

pdf = Prawn::Document.new page_size: 'A4')
pdf.text 'Hello, Prawn!'
IO.write('sample2.pdf', pdf.render)


文字列の出力位置を変更します。
text の代わりに draw_text を使います。

pdf.draw_text 'Hello, Prawn', at: [100, 100]


Prawn では印字範囲の左下が原点となり、そこから [ 右方向の距離, 上方向の距離 ] という形で位置を指定します(第一象限の (x, y) を指定する形です)。単位はポイント(72分の1インチ)です。


表示領域を指定し、その領域内の配置を指定することもできます。
そのばあいは text_box を使います。
次の例では、右から 100 ポイント、下から 100 ポイント、幅 100 ポイント、高さ 100 ポイントの範囲に、縦横とも中央寄せで出力します。

pdf.text_box 'Hello, Prawn!', at: [100, 100], width: 100, height: 20, align: :center, valign: :center

高さ (height) を指定するばあい、指定した位置から下方向の位置になるので注意が必要です



また「ポイントの計算が面倒臭い」というばあいのために、メートル法、ヤード法を使うための手段が用意されています。

prawn/measurement_extensions を使うと、.mm.cm といったメソッドが使えるようになります。

require 'prawn'
require 'prawn/measurement_extensions'

Prawn::Document.generate('sample.pdf', page_size: 'A4') do |pdf|
  pdf.draw_text 'Hello, Prawn', at: [100.mm, 100.mm]
end


標準では日本語フォントを持っていないので、日本語を表示させるばあいはフォントファイルを読み込ませる必要があります。
IPAフォントなどを用意します。
たとえば明朝体フォント ipaexm.ttf を設定するばあい次のように記述します。

# フォントの読み込みと設定
pdf.font('ipaexm.ttf')

あるいは

# フォントファルの読み込み
pdf.font_families.update('ipa-mincho' => {normal: {file: 'ipaexm.ttf'}})
# フォントの設定
pdf.font('ipa-mincho')


細かな設定は Prawn のドキュメントを参照してみてください。


捺印欄を作ってみる

これらを踏まえて。スタンプラリーの台紙 捺印欄のある書類を作成してみます。

require 'prawn'
require 'prawn/measurement_extensions'

# ファイル名 sample.pdf 、 用紙サイズ A4 、マージン を上 15mm 、右 15mm 、下 20mm 、左 25mm に設定した PDF ファイルを作る
# マージンの数字の並び(上右下左の並び)は CSS と同じ、また値が1つ、2つ、3つの場合の動作も CSS と同じ
Prawn::Document.generate('sample.pdf', page_size: 'A4', margin: [15.mm, 15.mm, 20.mm, 25.mm]) do |pdf|

  # 捺印欄の位置と幅高さ
  # 印字領域の右から 9cm 、上から 5cm の位置、幅 9cm 、高さ 2.5cm の領域に設定
  pdf.bounding_box([pdf.bounds.width - 90.mm, pdf.bounds.height - 50.mm], width: 90.mm, height: 25.mm) do
    # このブロック内では捺印欄の左下が原点

    # 太線の幅を指定
    pdf.line_width(1)

    # 枠を書く(bounding_box で指定した領域を覆う線を描く)
    pdf.stroke_bounds

    # 技術本部と技術部を分ける線
    pdf.horizontal_line(0.mm, 90.mm, at: 20.mm) # 横線:左から 0mm〜90mm までの横線を、高さ 20mm の位置に描く
    pdf.vertical_line(0.mm, 25.mm, at: 30.mm)   # 縦線:高さ 0mm〜25mm までの縦線を、左から 30mm の位置に描く

    # ここまでの線を描画
    pdf.stroke

    # 細線の幅を指定
    pdf.line_width(0.2)

    # 役職を分ける線
    pdf.horizontal_line(0.mm, 90.mm, at: 15.mm)
    pdf.vertical_line(0.cm, 20.mm, at: 15.mm)
    pdf.vertical_line(0.cm, 20.mm, at: 45.mm)
    pdf.vertical_line(0.cm, 20.mm, at: 60.mm)
    pdf.vertical_line(0.cm, 20.mm, at: 75.mm)

    # ここまでの線を描画
    pdf.stroke

    # フォントファルの読み込み
    pdf.font_families.update('ipa-mincho' => {normal: {file: 'fonts/ipaexm.ttf'}})

    # フォントの設定
    pdf.font('ipa-mincho')

    # フォントサイズ指定
    pdf.font_size(8)

    # 部門名
    pdf.bounding_box([0.mm, 25.mm], width: 90.mm, height: 5.mm) do
      pdf.text_box('技術本部', at: [0.mm, 5.mm], width: 30.mm, height: 5.mm, align: :center, valign: :center)
      pdf.text_box('技術部', at: [30.mm, 5.mm], width: 60.mm, height: 5.mm, align: :center, valign: :center)
    end

    # 役職名
    pdf.bounding_box([0.mm, 20.mm], width: 90.mm, height: 5.mm) do
      %w(本部長 副本部長 部長 課長 係長 担当).each_with_index do |pos, i|
      pdf.text_box(pos, at: [15.mm * i, 5.mm], width: 15.mm, height: 5.mm, align: :center, valign: :center)
      end
    end
  end
end

Ruby on Rails のレスポンスで PDF を返す

Prawn::Document.newPrawn::Document#render を使うことで Rails のレンスポンスとして生成した PDF を返すことができます。

  def show
    respond_to do |format|
      format.pdf do
        pdf = Prawn::Document.new(page_size: 'A4', margin: [15.mm, 15.mm, 20.mm, 25.mm])
        # PDF を構築(省略)
        send_data pdf.render, filename: "sample.pdf", type: "application/pdf", disposition: 'inline'
      end
    end
  end

いつか読むはずっと読まない:がんばれカミナリ

ブロントサウルスはアパトサウルスとは別属だったらしいという記事。

歩けば雷鳴が轟くごときだっただろうという想像から、雷竜〜ブロントサウルスという名称がつけられ、広く知られていたもののアパトサウルスと同属と判断され先名権により姿を消していた名称。
ここにきて復活するとは思いませんでした。


雷竜といえば、この書籍。

がんばれカミナリ竜〈上〉進化生物学と去りゆく生きものたち

がんばれカミナリ竜〈上〉進化生物学と去りゆく生きものたち

がんばれカミナリ竜〈下〉進化生物学と去りゆく生きものたち

がんばれカミナリ竜〈下〉進化生物学と去りゆく生きものたち

今回調べてみて、入手困難になっていることを知り、少なからずショックを受けました。


そしてグールド博士の最後のエッセイ集。日本語訳版がでてすぐに購入したのですが、これでおしまいかと思うと、もったいない感じがしてしまい、いまだに読めずにいます。

ぼくは上陸している (上): 進化をめぐる旅の始まりの終わり

ぼくは上陸している (上): 進化をめぐる旅の始まりの終わり

ぼくは上陸している (下): 進化をめぐる旅の始まりの終わり

ぼくは上陸している (下): 進化をめぐる旅の始まりの終わり