Sep 12, 2008

[Apple] フォルダアクションで docbook を PDF に変換する

Mac OS X 上に Docbook 環境を構築してみた。 やりたいのは、フォルダアクションで docbook を PDF 化すること。

docbook 環境のインストール

まずは MacPorts を使用して docbook 関連のライブラリと Apache FOP をインストールする。

$ sudo port install docbook-xml docbook-xsl libxslt fop
Password:
--->  Fetching xmlcatmgr
  (略)
--->  Installing xmlcatmgr 2.2_1
--->  Activating xmlcatmgr 2.2_1
--->  Cleaning xmlcatmgr
--->  Fetching docbook-xml-4.1.2
  (略)
--->  Installing docbook-xml-4.1.2 4.1.2_1
--->  Activating docbook-xml-4.1.2 4.1.2_1
--->  Cleaning docbook-xml-4.1.2
  (略)
--->  Installing docbook-xml-4.2 4.2_0
--->  Activating docbook-xml-4.2 4.2_0
--->  Cleaning docbook-xml-4.2
--->  Fetching docbook-xml-4.3
  (略)
--->  Installing docbook-xml-4.3 4.3_0
--->  Activating docbook-xml-4.3 4.3_0
--->  Cleaning docbook-xml-4.3
--->  Fetching docbook-xml-4.4
  (略)
--->  Installing docbook-xml-4.4 4.4_0
--->  Activating docbook-xml-4.4 4.4_0
--->  Cleaning docbook-xml-4.4
--->  Fetching docbook-xml-4.5
  (略)
--->  Installing docbook-xml-4.5 4.5_0
--->  Activating docbook-xml-4.5 4.5_0
--->  Cleaning docbook-xml-4.5
--->  Fetching docbook-xml
  (略)
--->  Installing docbook-xml 4.5_1
--->  Activating docbook-xml 4.5_1
--->  Cleaning docbook-xml
--->  Fetching docbook-xsl
  (略)
--->  Installing docbook-xsl 1.72.0_0
--->  Activating docbook-xsl 1.72.0_0
--->  Cleaning docbook-xsl
--->  Fetching libxslt
  (略)
--->  Installing libxslt 1.1.22_0
--->  Activating libxslt 1.1.22_0
--->  Cleaning libxslt
--->  Fetching fop
  (略)
--->  Installing fop 0.94_0
--->  Activating fop 0.94_0
--->  Cleaning fop
$

シングルバイトの docbook ファイルを PDF 化してみる

PDF の Font 周りは面倒なので、とりあえずはシングルバイト文字のみで PDF 化を試してみる。 用意したデータはこんな感じ。

<?xml version="1.0" encoding="UTF-8"?>

<book id="my_test_book">
  <title>my test book</title>
  <chapter id="chapter1">
    <title>Chapter 1</title>
    <para>Hello docbook!</para>
  </chapter>
  <chapter id="chapter2">
    <title>Chapter 2</title>
    <para>This is single byte docbook document.</para>
  </chapter>
</book>
docbook xml → (XSLT) → FO → (Apache FOP) → PDF という様に docbook を PDF に変換する。
$ /opt/local/bin/xsltproc -o ./test.fo /opt/local/share/xsl/docbook-xsl/fo/docbook.xsl ./test.xml
Making portrait pages on USletter paper (8.5inx11in)
$ fop -fo ./test.fo -pdf ./test.pdf
2008/09/10 11:45:21 org.apache.fop.hyphenation.Hyphenator getHyphenationTree
致命的: Couldn't find hyphenation pattern en
$ 
何事もなく PDF が生成された。
[PDF 化されたシングルバイト docbook]

マルチバイトの docbook ファイルを PDF 化してみる

次に本命のマルチバイト docbook ファイルの変換に挑戦してみる。 FOP のフォント設定は以下のサイトを参考にさせていただいた。感謝。

Apache FOP: Fonts
http://xmlgraphics.apache.org/fop/0.95/fonts.html#basics
DocBook メモ
http://cueplot.sourceforge.jp/wiki/index.php?DocBook%20%E3%83%A1%E3%83%A2
用意したデータはこんな感じ。
<?xml version="1.0" encoding="UTF-8"?>

<book id="my_test_book_ja">
  <title>テストブック</title>
  <chapter id="chapter1">
    <title>第一章</title>
    <para>やぁ! Docbook</para>
  </chapter>
  <chapter id="chapter2">
    <title>第二章</title>
    <para>日本語は上手く表示できるかな?</para>
  </chapter>
</book>
当然駄目だと分かっているが、とりあえずそのまま PDF 化してみる。 手順はシングルバイトのときと全く同様。
結果は
[やはり駄目]

やはり Font を設定しなければ化けることが分かったので、仕方なく Font を設定する。 手順は上記のサイトに記載がある通り。

$ cd /opt/local/share/java/fop/0.94/
$ java -cp ./build/fop.jar:./lib/commons-logging-1.0.4.jar:./lib/commons-io-1.3.1.jar org.apache.fop.fonts.apps.TTFReader -d -fn "HiraginoMinchoProW3" "/System/Library/Fonts/\343\203\222\343\203\251\343\202\255\343\202\231\343\203\216\346\230\216\346\234\235 Pro W3.otf" ./hiraginominchoprow3.xml
TTF Reader for Apache FOP 0.94

Parsing font...
Reading /System/Library/Fonts/?q???L??m???? Pro W3.otf...
sfnt version: OpenType with CFF data
  (略)
Font Family: Hiragino Mincho Pro
Error while building XML font metrics file.
java.lang.UnsupportedOperationException: OpenType fonts with CFF data are not supported, yet
        at org.apache.fop.fonts.apps.TTFReader.loadTTF(TTFReader.java:214)
        at org.apache.fop.fonts.apps.TTFReader.main(TTFReader.java:163)
・・・ ヒラギノは現時点の Apache FOP では扱えないらしい。 では、ということで、MS 明朝を試してみた。
$ java -cp ./build/fop.jar:./lib/commons-logging-1.0.4.jar:./lib/commons-io-1.3.1.jar org.apache.fop.fonts.apps.TTFReader -d -fn "MSMINCHO" "./fonts/MSMINCHO.TTF" ./fonts/msmincho.xml
TTF Reader for Apache FOP 0.94

Parsing font...
Reading /fonts/MSMINCHO.TTF...
sfnt version: OpenType 1.0
  (略)
Font Family: MS Mincho
Creating xml font file...
Creating CID encoded metrics...
Writing xml font file /fonts/msmincho.xml...
This font contains no embedding license restrictions.

XML font metrics file successfully created.
$ 
MS 明朝は正常に読み込むことができた。
後は FOP の設定ファイル fop.xconf を作成するだけ。
<?xml version="1.0"?>
<fop version="1.0">
 <renderers>
   <renderer mime="application/pdf">
     <fonts>
       <font metrics-url="/fonts/msmincho.xml" kerning="yes" embed-url="/fonts/MSMINCHO.ttf">
         <font-triplet name="MSMINCHO" style="normal" weight="100"/>
         <font-triplet name="MSMINCHO" style="normal" weight="200"/>
         <font-triplet name="MSMINCHO" style="normal" weight="300"/>
         <font-triplet name="MSMINCHO" style="normal" weight="400"/>
         <font-triplet name="MSMINCHO" style="normal" weight="500"/>
         <font-triplet name="MSMINCHO" style="normal" weight="600"/>
         <font-triplet name="MSMINCHO" style="normal" weight="700"/>
         <font-triplet name="MSMINCHO" style="normal" weight="800"/>
         <font-triplet name="MSMINCHO" style="normal" weight="900"/>
       </font>
     </fonts>
   </renderer>
 </renderers>
</fop>

ではマルチバイト docbook の PDF 化に再挑戦。 今回は MS 明朝を使用するので、docbook から FO を作成した後で FO 内の Font 設定を変更する処理を入れる。 docbook → (XSLT) → fo → (sed) → fo → (FOP) → PDF という感じになる。 また、Apache FOP 実行時に上で作成した設定ファイルを指定する必要がある。

$ /opt/local/bin/xsltproc -o ./test_ja.fo /opt/local/share/xsl/docbook-xsl/fo/docbook.xsl ./test_ja.xml
Making portrait pages on USletter paper (8.5inx11in)
$ sed -e "s/font-family=\"/font-family=\"MSMINCHO,/g" ./test_ja.fo > ./test_ja_2.fo
$ fop -fo ./test_ja_2.fo -pdf ./test_ja_2.pdf -c ./fop.xconf 
2008/09/10 13:14:28 org.apache.fop.hyphenation.Hyphenator getHyphenationTree
?v???I: Couldn't find hyphenation pattern en
$ 
マルチバイト docbook の PDF 化に成功!!
[日本語も表示できた!!]

AppleScript で docbook → PDF の変換を行う

docbook の PDF 化に成功したところで、念願の AppleScript での変換を行う。 まずはシェルスクリプトを用意。

#!/bin/sh

DOCBOOK_XML=$1
DOCBOOK_PDF=$2

XSLTPROC=/opt/local/bin/xsltproc
DOCBOOK_XSLT=/opt/local/share/xsl/docbook-xsl/fo/docbook.xsl
FOP=/opt/local/bin/fop
FOP_CONFIG=/fonts/fop.xconf
WORKDIR=`pwd`
WORK_FO=$WORKDIR/tmp.fo
WORK_FO_CONVERTED=$WORKDIR/tmp_converted.fo

echo "Converting docbook -> PDF : $DOCBOOK_XML -> $DOCBOOK_PDF"

if [ ! -f "$DOCBOOK_XML" ];
  then
    echo "No docbook file found. : $DOCBOOK_XML"
    exit;
fi

rm "$WORK_FO" 2> /dev/null
rm "$WORK_FO_CONVERTED" 2> /dev/null

$XSLTPROC -o "$WORK_FO" "$DOCBOOK_XSLT" "$DOCBOOK_XML"
sed -e "s/font-family=\"/font-family=\"MSMINCHO,/g" "$WORK_FO" > "$WORK_FO_CONVERTED"
$FOP -fo "$WORK_FO_CONVERTED" -pdf "$DOCBOOK_PDF" -c "$FOP_CONFIG"

rm "$WORK_FO" 2> /dev/null
rm "$WORK_FO_CONVERTED" 2> /dev/null
次にこのシェルスクリプトを呼び出す AppleScript を用意する。 この AppleScript は "/Library/Scripts/Folder Action Scripts/Image - Duplicate as JPEG.scpt" を参考にさせていただいた(「参考に」と言うより、ほぼそのまま)。
property doneFoldername : "PDF"
property originalsFoldername : "Docbook"
property pdfExtension : "pdf"
property typeList : {"XML"}
property extensionList : {"xml"}

on adding folder items to thisFolder after receiving theseItems
  tell application "Finder"
    if not (exists folder doneFoldername of thisFolder) then
      make new folder at thisFolder with properties {name:doneFoldername}
    end if
    set the resultsFolder to (folder doneFoldername of thisFolder) as alias
    if not (exists folder originalsFoldername of thisFolder) then
      make new folder at thisFolder with properties {name:originalsFoldername}
      set current view of container window of thisFolder to list view
    end if
    set the originalsFolder to folder originalsFoldername of thisFolder
  end tell
  try
    repeat with i from 1 to number of items in theseItems
      set thisItem to item i of theseItems
      set the itemInfo to the info for thisItem
      if (alias of the itemInfo is false and the file type of the itemInfo is in the typeList) or (the name extension of the itemInfo is in the extensionList) then
        tell application "Finder"
          my resolveConflicts(thisItem, originalsFolder, "")
          set the newName to my resolveConflicts(thisItem, resultsFolder, pdfExtension)
          set the SourceFile to (move thisItem to the originalsFolder with replacing) as alias
        end tell
        processItem(SourceFile, newName, resultsFolder)
      end if
    end repeat
  on error errorMessage number errorNumber
    if the errorNumber is not -128 then
      tell application "Finder"
        activate
        display dialog errorMessage buttons {"Cancel"} default button 1 giving up after 120
      end tell
    end if
  end try
end adding folder items to

on resolveConflicts(thisItem, targetFolder, newExtension)
  tell application "Finder"
    set the fileName to the name of thisItem
    set fileExtension to the name extension of thisItem
    if the fileExtension is "" then
      set the trimmedName to the fileName
    else
      set the trimmedName to text 1 thru -((length of fileExtension) + 2) of the fileName
    end if
    if the newExtension is "" then
      set targetName to fileName
      set targetExtension to fileExtension
    else
      set targetExtension to newExtension
      set targetName to (the trimmedName & "." & targetExtension) as string
    end if
    if (exists document file targetName of targetFolder) then
      set the nameIncrement to 1
      repeat
        set the newName to (the trimmedName & "." & (nameIncrement as string) & "." & targetExtension) as string
        if not (exists document file newName of the targetFolder) then
          set the name of document file targetName of the targetFolder to the newName
          exit repeat
        else
          set the nameIncrement to the nameIncrement + 1
        end if
      end repeat
    end if
  end tell
  return the targetName
end resolveConflicts

on processItem(SourceFile, newName, resultsFolder)
  try
    set the targetPath to ((resultsFolder as string) & newName) as string
    with timeout of 900 seconds
      do shell script "/Scripts/convert-docbook.sh ¥"" & POSIX path of SourceFile & "¥" ¥"" & POSIX path of targetPath & "¥""
    end timeout
  on error errorMessage
    tell application "Finder"
      activate
      display dialog errorMessage buttons {"Cancel"} default button 1 giving up after 120
    end tell
  end try
end processItem
この AppleScript をフォルダに関連付けて今回の作業は終了。

Posted in Apple | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |