2011年12月16日金曜日

ConfluenceのHTML→PDF変換ライブラリを利用する

JIRA Advent Calendar 2011、15日目です。

ってすみません、ConfluenceネタですがまあJIRA使ってる人は連携して使ったりしますよねとか、そんな感じで。
GradleのユーザーガイドPDFに変換するときにお世話になったので、紹介してみます。

Confluenceは、バンドルされているプラグインでページをPDFに変換して出力できるのですが、この機能に使われているライブラリを使って、XHTMLをPDFに変換しようという話です。

ConfluenceのXHTML→PDF処理にはFlying SaucerというJavaのライブラリが使われています。
Flying Saucerを使うと、XMLやXHTMLファイルを、PDFやSWT、Swingのスクリーンに出力させることができます。デザインはCSSで指定できます。

ただ、このFlying Saucer、PDFに変換したときに、文字列が空白位置でしか改行されません。
英文Onlyならいいのですが、日本語で長文をだらだら書いていると画面外にあふれて見えなくなってしまうわけですね。
ConflueceのPDFエクスポートでの禁則 - azuki note

この問題を、Atlassianさんがパッチを当てて修正しているので、しかもMavenリポジトリ上に上げてくれているので、今回はそれを使います。

@Grape+Groovyスクリプトでもいいですが、いろいろ面倒なのでGradleスクリプトで。

フルのサンプルはGithubに上げたのでそちらを見てもらうとして、ポイントだけ書いておきます。

変換元のHTMLとCSSのサンプル

AtlassianさんのMavenリポジトリからFlying Saucerを取得

AtlassianさんのMavenリポジトリから、パッチの当たったFlying Saucerライブラリを取得します。
GradleとかMavenとかIvyとか、そのあたりの設定に依存関係を追加するのがいいですね。

ライセンスが気になるところですが、LGPLのままみたいなので大丈夫でしょう、多分…

Mavenリポジトリ
https://maven.atlassian.com/repository/public
アーティファクト
org.xhtmlrenderer:xhtmlrenderer:8.3-atlassian

Flying SaucerはPDF生成にiTextを使うのでそちらも

Mavenリポジトリ
セントラルリポジトリ
アーティファクト
com.lowagie:itext:2.0.8
// Gradleの例
buildscript {
    repositories {
        mavenCentral()
        mavenRepo url: "https://maven.atlassian.com/repository/public"
    }
    dependencies {
        classpath "org.xhtmlrenderer:xhtmlrenderer:8.3-atlassian"
        classpath "com.lowagie:itext:2.0.8"
    }
}

PDFへの変換処理

PDFへの変換処理は、次のような感じで書きます。

import org.xhtmlrenderer.pdf.ITextRenderer

def renderer = new ITextRenderer()
renderer.setDocument(new File("sample.html"))
renderer.layout()
new File("sample.pdf").withOutputStream {
    renderer.createPDF(it)
}

このコードを実行すれば、sample.htmlがsample.pdfに変換されます。

CSSでPDFに埋め込むフォントを指定する

日本語を使うには日本語フォントをPDFに埋め込むか参照させる必要があります。変換元のHTMLに次のようなCSSを適用しましょう。

@font-face{
    font-family: "IPAexGothic";
    src: url(ipaexg.ttf);
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: Identity-H;
}

body {
    font-family: "IPAexGothic";
}

なんか、使えるフォントと使えないフォントがあるみたいです。

fsなんたらはFlying Saucerのベンダー拡張ですね。詳しくはFlying Saucerのユーザーガイドを見てみてください。

長い文章を折り返すための設定

Atlassianさんのパッチが当たったFlying Saucerを使うと、次のようにCSSでword-wrapを指定することで長い文章が折り返されるようになります。

p {
    word-wrap: break-word;  
}

おわりに

いやぁ、便利ですね。ちょっとしたPDF作るだけなら、それ用のHTMLファイル作って変換するのが簡単かもしれません。

さて、かなり脱線気味でしたが、こんなところで。
引き続きJIRA Advent Calendar 2011をお楽しみください。

2011年12月6日火曜日

GrailsのプラグインリポジトリとしてGithubを使う

G* Advent Calendar、6日目いってみます。
今日を境に、公開Grailsプラグインの数が爆発的に増える……といいなーという感じで

Grails version
2.0.0.RC1

Grailsプラグインのリポジトリには、Maven形式のリポジトリが使用できます。

つまり、MavenのリモートリポジトリをGithub上に構築する以下の手法を使えば、GraisプラグインのリポジトリをGithub上に持てるわけですね。
Github を Maven 公開リポジトリにする
GitHub を Maven 公開リポジトリにする (Gradle 編)

何ができるの?

例えば、私はGrailsのAWSプラグインにパッチを当てたものをGithub上に公開しています。1

このプラグインは、次のようにしてどこからでも使用できます。

// grails-app/conf/BuildConfig.groovy
// ...
grails.project.dependency.resolution = {
    // ...
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()

        // ...
        // Github上のマイプラグインリポジトリを指定
        mavenRepo "http://literalice.github.com/maven-repo/releases"
    }
}

# 上で指定したプラグインリポジトリからプラグインをインストール
cd grails-project
grails install-plugin aws 1.2.12.1.p1

とまあ、このように、改造したり開発したりした非公式オリジナルプラグインを簡単に公開して使えるようにしちゃおうというのが目的です。

GrailsのプラグインはzipファイルのURLを指定してインストールできるので他にいくらでも方法はあるわけですが、不特定多数に公開して良いなら今のところこれが一番手軽なんじゃないかなぁと。

この記事は、私がAWSプラグインを改造して公開したときの手順を思い出しながら書いていますが、オリジナルのプラグインを公開するときも同じような感じです。

以下がその手順です。

プラグインのソースコードを入手する

  • Github上にあるプラグインのソースコードをフォークして、手元にクローン
  • grails create-plugin コマンドでプラグインプロジェクトを作成する
  • などなど

プラグインのバージョン番号を更新する

既存のプラグインを改造する場合は、バージョン番号がオリジナルのものと被らないように変更しておいた方が良いでしょう。1.0.0.p1、といった風に適当なサフィックスを付けておきます。

    // XXGrailsPlugin.groovy - プラグインディスクリプタ
    // ..
    def version  = "1.0.0.p1"
    // ..

GrailsのReleaseプラグインをインストールする

プラグインのビルド、リポジトリへの公開は、このReleaseプラグインを使います。

Grails2系のcreate-pluginでプラグインプロジェクトを作成した場合は既にプロジェクトにインストールされているかと思いますが、そうでなければ自分でインストールする必要があります。

install-pluginコマンドでインストールせず、必ずBuildConfig.groovy上でプラグインを追加してexport設定を追加します。そうでないと、このマイプラグインをインストールしたときに、インストール先のプロジェクトもreleaseプラグインに推移的に依存するようになってしまいますので。

ちなみにAWSプラグインはinstall-pluginでreleaseプラグインをインストールしていたようなので、改造版ではこちらも修正しています。

// grails-app/conf/BuildConfig.groovy
// ...
grails.project.dependency.resolution = {
    // ...
    plugins {
        // ...
        build(':release:1.0.0.RC3') {
            export = false // このプラグインはインストール先のプロジェクトには不要
        }
    }
}

プラグインをがしかし実装

プラグインをオレオレに改造します。がしかし好きな機能を実装します。

Github上にMavenリポジトリを構築する

好きな機能は実装できましたか? ではプラグインを公開しましょう。

Github を Maven 公開リポジトリにする
を参考に、MavenリポジトリをGithub上に構築します。

おおざっぱに言えば、

  1. ローカルにフォルダを作ります(「D:\mvn」など)。
  2. そのフォルダをgitのリポジトリとして初期化します。
  3. そのリポジトリに「gh-pages」という名前のブランチを作ります。
  4. 作った「gh-pages」ブランチをgithubにプッシュします
  5. おわり

後は、このフォルダにMavenリポジトリ構造でファイルを追加してプッシュすれば、Github上にそのファイルを公開できるわけですね

ここでは、「D:\mvn」にgitのリポジトリを作ったものとします。

ローカルフォルダにGrailsプラグインをリリースする

先ほどgitリポジトリとして初期化したフォルダ「D:\mvn」にプラグインをリリースします。

Grailsのreleaseプラグインは、SubversionリポジトリやリモートのWebDAV Mavenリポジトリにプラグインをリリースできますが、ローカルにはき出すことも可能なようです。

リリース先の指定方法はreleaseプラグインのマニュアルに載っています。

プロジェクトのBuildConfig.groovyか、ユーザーのホームディレクトリにsettings.groovyというファイルを置いて設定することができます。

バージョン管理に入れるであろうBuildConfig.groovyに、ローカルのファイルパスを書き込むというのはダサい気がするので、私はsettings.groovyを使いました。以下のように設定します。

// ~/.grails/settings.groovy
grails.release.scm.enabled = false // プラグインのソースコードはリリースしない

grails.project.repos.default = "localRelease" // リリース先未指定時のリリース先
grails.project.repos.localRelease.url = "file:///D:/mvn" // リリース先"localRelease"のURL

設定が終わったら、プラグインのプロジェクトディレクトリに移動して、リリースコマンドを実行します。2

cd my-grails-plugin
grails publish-plugin

コマンドが正常に終了すれば、「D:\mvn」にプラグインのzipファイル、pomファイルなどが生成されているはずです。3

MavenリポジトリをGithubにプッシュ

「D:\mvn」に生成された全てのファイルをコミットし、github上にプッシュします。

これで、作成したプラグインをどこからでも使用できるようになりました。

公開したプラグインを使う

公開したプラグインは、前述のように「BuildConfig.groovy」にGithub上のプラグインリポジトリを追加すれば使用できます。

リポジトリのURLは、Githubユーザー名が「literalice」、プッシュしたMavenリポジトリのフォルダ名が「mvn」であれば、「http://literalice.github.com/mvn」となります。

// grails-app/conf/BuildConfig.groovy
// ...
grails.project.dependency.resolution = {
    // ...
    repositories {
        // ...
        // Github上のマイプラグインリポジトリを指定
        mavenRepo "http://literalice.github.com/mvn"
    }
}

# 上で指定したプラグインリポジトリからプラグインをインストール
cd grails-project
grails install-plugin myplugin 1.0.0.p1

Twitterとかで通知

使って欲しい人に向けて、プラグインのリリース情報を通知します。プラグインリポジトリのURLとプラグイン名、プラグインバージョンを教えてあげれば大丈夫なはず。

まとめ

これでもう、プラグインのバグ修正も機能追加も待つ必要ないですね。直して公開です。

わざわざGrailsの公式リポジトリにプラグインを公開する必要もないですね。プラグイン名とリポジトリのURLを一緒に教えてあげれば大丈夫です。

気が向きましたら、本家にpull requestとか、プラグインを公式リポジトリに公開とかするとよりナイスですね。

Githubの最大容量は300MBらしいですが、普通のプラグインはそんなに容量大きくならないので大丈夫じゃないでしょうか、多分。

G* Advent Calendar、7日目は@masanobuimaiさんです。



注1: AWSプラグインは、GrailsからAmazon Web Serviceを簡単に使えるようにするものですが、SESでメールを送信するときに文字セットを指定できなかったためパッチを当てて使っています。

注2: 本来であれば、

cd my-grails-plugin
grails publish-plugin --repository=localRelease
とすることで、リリース先を明示的に指定できるはずなのですが、私の環境ですと上手く動かなかったので、デフォルトのリリース先をsettings.groovyで設定して、リリース先を指定せずにリリースできるようにしています。

注3: 「WARNING: unknown protocol 'file' for repository」というワーニングが出るのが気になりますが…とりあえず、問題なくリリースできるようです。