2012年

7月

24日

[TIPS]任意の図形を描画する方法

Field Reportsには,線・矩形・円・多角形などの図形を描画する機能はありません。 

動的に図形を描画する必要が生じた場合にどうしたら良いのか考えてみました。

フィールドの境界線・塗りつぶしで表現する方法

値が空のテキストフィールドを作成して,境界線・塗りつぶし色を指定すれば矩形が表示できます。

また,高さ・幅を狭く設定すれば線分を表現することができます。

 

以下に,作成したレンダリング・パラメータを示します。

 

PDFを作成するには,以下のコマンドラインプログラムを実行します。

 

$ reports create draw.json out.pdf

// draw.json
{
    "template": {"paper": "A4"},
    "context": {
        "rect1": {
            "new": "Tx",
            "rect": [100, 700, 200, 800],
            "border-width": 5,
            "border-color": "Gray",
            "background-color": "Yellow",
            "border-join-style": "RoundJoin"
        },
        "rect2": {
            "new": "Tx",
            "rect": [250, 700, 350, 750],
            "border-width": 3,
            "rotation": 15,
            "border-width": 3,
            "border-color": "Green",
            "background-color": "Olive",
            "border-join-style": "RoundJoin"
        },
        "line1": {
            "new": "Tx",
            "rect": [100, 650, 400, 651],
            "background-color": "Red"
        },
        "line2": {
            "new": "Tx",
            "rect": [200, 500, 201, 640],
            "background-color": "Blue"
        }
    }
}
実行結果
実行結果

図形描画ライブラリを利用する方法

さらに複雑な図形を描画する必要がある場合は,別のグラフィックライブラリを使用する方法もあります。

グラフィックライブラリで作成した画像をField Reportsに取り込んで合成することができます。

 

ここでは,代表的な2DグラフィックスライブラリであるcairoをPythonから使用した例をご紹介します。

 

cairoの出力形式としてPDFを指定し,作成したPDFのデータをURIデータスキーマ形式でField Reportsに渡しています。

 

$ python draw.py

#!/usr/bin/env python

import math
import cairo
import StringIO
import base64
from field import reports

def draw(pdf):
    WIDTH, HEIGHT = 256, 256
    surface = cairo.PDFSurface (pdf, WIDTH, HEIGHT)
    ctx = cairo.Context (surface)
    ctx.scale (WIDTH, HEIGHT)
    ctx.translate (0.1, 0.1)
    ctx.move_to (0, 0)
    ctx.arc (0.2, 0.1, 0.1, -math.pi/2, 0)
    ctx.line_to (0.5, 0.1)
    ctx.curve_to (0.5, 0.2, 0.5, 0.4, 0.2, 0.8)
    ctx.close_path ()
    ctx.set_source_rgb (0.3, 0.2, 0.5)
    ctx.set_line_width (0.02)
    ctx.stroke ()
    surface.finish()

def urischeme(data):
    return 'data:application/pdf;base64,' + base64.b64encode(data)

param = {
    "template": {"paper": "A4"},
    "resources": {
        "image": {
            "cairo": "",
        },
    },
    "context": {
        "hello": {
            "new": "Tx",
            "value": "Hello, World!",
            "color": "Red",
            "rect": [150, 550, 450, 650]
        },
        "cairo": {
            "new": "Btn",
            "image": "cairo",
            "rect": [50, 500, 350, 800],
            "border-width": 3,
        }
    }
}

if __name__ == "__main__":
    pdf = StringIO.StringIO()
    draw(pdf)
    data = urischeme(pdf.getvalue())
    param["resources"]["image"]["cairo"] = data
    reports.set_log_level(5)
    reports.render(param, "out.pdf")
    
実行例
実行例