FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

書類送付状生成デモの作成

前回のはがき宛名面の作成デモに続いて,書類送付状を作成するデモを作成しました。

実用的にも使えると思いますので,よかったら使ってみてください。

テンプレートの作成

まずは,オフィスソフトを利用して,帳票のレイアウトをデザインします。

今回は,長形3号の窓付き封筒で使えるように宛先欄を左上に配置しました。 Mac OS X 用の表計算ソフト Numbers を使用して元原稿を作成し,PDF形式で書き出しました。

次に,Adobe Acrobat Professional で作成したPDFを開き,テキストを動的に埋め込む位置にフォーム・フィールドを配置していきます。

基本的には,フォント・フォントサイズ・表示色などの表示属性をこの時決めて設定しますが, 帳票生成時にプログラムから指定することもできます。

テーブル形式のフィールドを配置する際には,基準となるフィールドを配置してから,「複数のフィールドを配置...」で必要な数だけ複製します。

以上で,テンプレートが完成しました。

因みに Field Reports では,フォーム・フィールドをテキストの表示位置やフォント指定などの属性を取得するためのプレース・フォルダとして利用しているにすぎません。テキストを配置した後は削除され,最終的に作成される帳票には残りません。

プログラムの作成

今回もフレームワークとしてweb2pyを使用しました。 controller部のコードを以下に示します。

「if form.accepts(request.vars):」以降で Field Reports に渡すパラメータを組み立てています。 基本的には,Webのフォームにつけた名前とPDFテンプレートに配置したフィールドの名前を一致させているので, form.varsの値がそのまま使えますが,テーブル形式の部分はリスト形式にする必要があるので, この部分の変換を行なっています。

render関数の中では,テンプレートの場所などその他のパラメータを追加して実際に Field Reports のAPIを呼び出しています。

# coding: utf8

from gluon.contrib import simplejson
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
import tools

def index():
    def docinput(num):
       return TR(TD(INPUT(_name='_no'+str(num), _size=5)),
                 TD(INPUT(_name='_document'+str(num), _size=60)),
                 TD(INPUT(_name='_count'+str(num), _size=5)))
    form = FORM(
        UL(LI(LABEL(u'日付'), INPUT(_name="date", _value="")),
           FIELDSET(LEGEND(u'宛先'),
               LI(LABEL(u'郵便番号'), INPUT(_name='to_post', _size=8)),
               LI(LABEL(u'住所1'), INPUT(_name='to_address1', _size=30)),
               LI(LABEL(u'住所2'), INPUT(_name='to_address2', _size=30)),
               LI(LABEL(u'会社名'), INPUT(_name='to_company', _size=30)),
               LI(LABEL(u'氏名'), INPUT(_name='to_name', _size=30))),
           FIELDSET(LEGEND(u'差出人'),
               LI(LABEL(u'郵便番号'), INPUT(_name='from_post', _size=8)),
               LI(LABEL(u'住所1'), INPUT(_name='from_address1', _size=30)),
               LI(LABEL(u'住所2'), INPUT(_name='from_address2', _size=30)),
               LI(LABEL(u'会社名'), INPUT(_name='from_company', _size=30)),
               LI(LABEL(u'氏名'), INPUT(_name='from_name', _size=30)),
               LI(LABEL(u'連絡先1'), INPUT(_name='from_contact1', _size=30)),
               LI(LABEL(u'連絡先2'), INPUT(_name='from_contact2', _size=30))),
           FIELDSET(LEGEND(u'送付物'),
               TABLE(
                   TR(TH(u'No.'), TH(u'書類名'), TH(u'部数')),
                   docinput(0), docinput(1), docinput(2), docinput(3),
                   docinput(4), docinput(5), docinput(6), docinput(7),
                   docinput(8), docinput(9), docinput(10))),
           LI(INPUT(_type='submit', _value='帳票出力'),
              INPUT(_type='reset', _value='リセット'), _align='right'), _id="simple"))

    if form.accepts(request.vars):
        response.flash = u'入力を受け付けました'
        context = form.vars
        context['no'] = [form.vars['_no'+str(i)] for i in range(11)]
        context['document'] = [form.vars['_document'+str(i)] for i in range(11)]
        context['count'] = [form.vars['_count'+str(i)] for i in range(11)]
        response.headers['Content-Type'] = 'application/pdf'
        response.headers['Content-Disposition'] = 'attachment; filename="cover.pdf"'
        return render(context)
    elif form.errors:
        response.flash = u'入力に誤りがあります'
    else:
        response.flash = u'フォームに入力してください'
    return dict(form=form)

def render(context):
    import os
    from field import reports
    import gluon.fileutils
    settings = {
        'template-root': os.path.join(gluon.fileutils.abspath('applications',
            request.application), 'resources'),
    }
    template = 'templates/sofu.pdf'
    params = {
        'settings': settings,
        'template': template,
        'context': context,
    }
    reports.set_defaults({})
    reports.set_log_level(3)
    return reports.renders(params)

実行例

以下に実際の実行例を示します。

参照

書類送付状生成デモの改造

Google App Engine からPDF帳票を生成する

Google App Engine (GAE) から Field Reports for Cloud β版で提供しているWeb APIサービスを用いて,帳票を生成する方法を解説します。

今回は,「Hello World!」を表示するデモを作成します。

プログラムの作成

Webアプリケーションフレームワークとしてweb2pyを使用しました。

web2pyで作成したアプリケーションの controllers/default.py に以下のコードを追加します。

<APIキー>の部分には,Field Reports for Cloud β版のサイトで取得したAPIキーを挿入します。

from gluon.contrib import simplejson
import urllib

def hello():
    params = {
        "settings": {
            "api-key": "<APIキー>"
        },
        "template": {"paper": "A4"},
        "context": {
            "hello_1": {
                "new": "Tx",
                "value": "Hello, World!",
                "rect": [100, 700, 400, 750],
                "font": "/Times-Roman"
            },
            "hello_2": {
                "new": "Tx",
                "value": "Hello, World!",
                "rect": [100, 600, 400, 650],
                "font": "/Helvetica-Oblique"
            },
            "hello_3": {
                "new": "Tx",
                "value": "Hello, World!",
                "rect": [100, 500, 400, 550],
                "font": "/Courier-Bold"
            },
            "hello_4": {
                "new": "Tx",
                "value": "ABCDEFGHIJKLMN",
                "rect": [100, 400, 400, 450],
                "font": "/ZapfDingbats"
            },
            "hello_5": {
                "new": "Tx",
                "value": "こんにちは世界",
                "rect": [100, 300, 400, 350],
                "font": "/KozGo-Medium"
            }
        }
    }
    url = "https://labs.field-works.co.jp/webapi/render"
    f = urllib.urlopen(url, simplejson.dumps(params))
    response.headers['Content-Type'] = 'application/pdf'
    return f.read()

アプリケーションのデプロイ

ローカル環境で動作確認を行ったら,作成したアプリケーションをGAEにデプロイします。 具体的なデプロイ手順については,参照サイト等を参照してください。

デモの実行

以下のURLにアクセスすると,生成したPDFを開きます。

http://field-reports.appspot.com/hello

参照サイト

CentOSにnginx+web2pyをインストール

さくらVPS上にnginx+web2pyの構成でWEBサーバを設定する手順をまとめました。 CentOSであれば,概ね同様の手順でインストールできると思います。

前提として,web2pyのファイルは /var/www/web2py に置いているものとします。

nginxのインストール

nginxの公式サイトに書いてあるとおり,yumリポジトリを追加してyumでインストールしてみました。

$ sudo vim /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

$ sudo yum install nginx

uWSGIのインストール

uWSGIは,pipを使ってインストールしました。

$ sudo yum update
$ sudo yum install python-devel
$ sudo yum install libxml2-devel
$ sudo yum install python-pip

$ sudo pip-python install uwsgi

nginxの設定

web2pyに添付されているスクリプト setup-web2py-nginx-uwsgi-ubuntu.sh の中身を切り出して,以下の設定ファイルを作成しました。

$ sudo vim /etc/nginx/conf.d/web2py.conf

server {
        listen          80;
        server_name     $hostname;
        location ~* /(\w+)/static/ {
           root /var/www/web2py/applications/;
        }
        location / {
                uwsgi_pass      127.0.0.1:9001;
                include         uwsgi_params;
                uwsgi_param     UWSGI_SCHEME $scheme;
                uwsgi_param     SERVER_SOFTWARE    nginx/$nginx_version;
        }
}

server {
        listen          443;
        server_name     $hostname;
        ssl                     on;
        ssl_certificate         /etc/nginx/ssl/web2py.crt;
        ssl_certificate_key     /etc/nginx/ssl/web2py.key;
        location / {
                uwsgi_pass      127.0.0.1:9001;
                include         uwsgi_params;
                uwsgi_param     UWSGI_SCHEME $scheme;
                uwsgi_param     SERVER_SOFTWARE    nginx/$nginx_version;
        }

}

HTTPS接続を行う場合は,サーバ証明書と秘密鍵を用意して /etc/ngin/ssl 配下に置きます。

uWSGIの設定

uWSGIの設定は,以下の記事を流用させて頂きました。

まず,uWSGIの設定ファイルを作成します。

$ sudo vim /etc/uwsgi.yaml

uwsgi:
  socket: 127.0.0.1:9001
  pythonpath: /var/www/web2py
  module: wsgihandler
  processes: 2
  daemonize: /var/log/uwsgi-web2py.log
  touch-reload: /tmp/reload.txt

最後のtouch-reloadで指定したファイルをtouchコマンドで更新してやると, ソースの修正が反映される仕組みになっています。 uwsgiとDjangoとリロードに, 自動的に反映させる方法が書いてありましたが,こちらは試していません。

次に,uWSGIの起動スクリプトを作成します。

$ sudo vim /etc/sysconfig/uwsgi

# Configuration file for the uwsgi service.

UWSGI=/usr/bin/uwsgi
CONFFILE=/etc/uwsgi.yaml
LOCKFILE=/var/lock/subsys/uwsgi

$ sudo vim /etc/init.d/uwsgi

#!/bin/sh
#
# uwsgi - this script starts and stops the uwsgi daemon
#
# chkconfig: - 85 15
# processname: uwsgi
# config: /etc/uwsgi.yaml
# config: /etc/sysconfig/uwsgi
# pidfile: /var/run/uwsgi.pid
# description: uwsgi is a WSGI server
#

# Source function library.
. /etc/rc.d/init.d/functions

CONFFILE="/etc/uwsgi.yaml"

if [ -f /etc/sysconfig/uwsgi ]; then
        . /etc/sysconfig/uwsgi
fi

prog=uwsgi
uwsgi=${NGINX-/usr/bin/uwsgi}
conffile=${CONFFILE-/etc/uwsgi.yaml}
lockfile=${LOCKFILE-/var/lock/subsys/uwsgi}
pidfile=${PIDFILE-/var/run/uwsgi.pid}
RETVAL=0

start() {
    echo -n $"Starting $prog: "

    #daemon --pidfile=${pidfile} ${uwsgi} --yaml ${conffile}
    daemon ${uwsgi} --yaml ${conffile} --pidfile ${pidfile}
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && touch ${lockfile}
    return $RETVAL
}

stop() {
    echo -n $"Stopping $prog: "
    killproc -p ${pidfile} ${prog} -INT
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}

# See how we were called.
case "$1" in
  start)
     start
     ;;
  stop)
     stop
     ;;
  status)
        status -p ${pidfile} ${uwsgi}
     RETVAL=$?
     ;;
  restart)
     stop
     start
     ;;
  *)
     echo $"Usage: $prog {start|stop|restart|status}"
     RETVAL=2
esac

exit $RETVAL

$ sudo chmod +x /etc/init.d/uwsgi

作成した起動スクリプトをサービスとして登録します。

$ sudo chkconfig --add uwsgi
$ sudo chkconfig on

サービスを開始

最後に,uWSGIとnginxのサービスを開始させます。

$ sudo service uwsgi start
$ sudo service nginx start

参照サイト

はがきの宛名印刷用PDF作成サービスを公開します

弊社製品のPDF帳票開発ツール Field Reportsを使って, はがき宛名面の印刷用PDFを生成するサービスを作成しました。

当初は単に製品のデモとして作り始めたのですが, 意外と実用的なものができたので, Webサービスとして一般に公開したいと思います。

サービスの概要

URLは, http://labs.field-works.co.jp/labs/atena/form です。

フォームに宛名と差出人の住所・氏名を入力して「帳票出力」ボタンを押すと,PDFを生成します。 プリンターで生成されたPDFをはがきに印刷すれば,宛名面の印刷ができます。

本サービスはフォームから入力して利用するだけでないく,Web API として機能を呼び出すこともできます。 Web API を介しての利用方法については,次回説明します。

入力フォーム

宛名(個別入力)

「宛名指定方法」欄の「個別入力」ラジオボタンを選択すると, 宛名をフォームで一件ごとに入力するモードになります。

このモードで作成できるのは,1ページのPDFのみです。

宛名(一括入力)

「宛名指定方法」欄の「一括入力」ラジオボタンを選択すると, CSVファイルで一括して宛名を指定するモードになります。

CSVファイルとCSVファイルの文字コードを指定してください。 CSVファイルの書式については,後述します。

差出人

差出人の郵便番号と住所を入力します。

レイアウト

横書きと縦書きの2種類のテンプレートを用意しています。

横書き 縦書き

位置の調整

プリンターの特性により印刷位置がずれる場合に調節してください。

CSVファイルの書式

カンマ区切りのCSVファイルとします(Excel形式のCSVファイルを想定しています)。

1行目にフィールド名,2行目以降にフィールドに対応するデータを記述してください。 使用できるフィールド名は以下のとおりです。

フィールド名 説明
post1 郵便番号上3桁
post2 郵便番号下4桁
address1 住所1行目
address2 住所2行名
company 会社名・団体名
title 肩書き
name 氏名

データ数は最大100件です。 101件目以降のデータは無視されます。

記述例

post1,post2,address1,address2,company,title,name
163,8001,東京都新宿区西新宿二丁目8番1号,,東京都庁,知事,石原 慎太郎 様
460,8501,愛知県名古屋市中区三の丸三丁目1番2号,,愛知県庁,知事,大村 秀章 様