PythonのCairoでSVGをつくる

最近、Android用のキーボードの開発をやってます。

0からつくるわけにはいかんので、Mozc for Androidってのを使ってるんですが、
こことかにも書かれてるみたいに、Mozcにはキートップの画像が含まれていません。
(正確に言うと、画像はありますが無刻印キーボード的な画像が含まれています)



なので、ビルドするとこんなかんじになります。


キーボードの配列を覚える練習にはなるかもしれませんが、実用的ではないですね。


そんなMozcを↑のようにしたいわけですが、
ここのページで公開されてるキートップ画像では[t][y][u]の上下が微妙にずれていて、若干気持ちが悪いです。そこで、キートップ画像の自作をすることにしました。


ただ、社会人が片手間にやるには、InkScapeでチマチマと作る時間がありません。
そんなわけで、Pythonで一気に作っちゃいました、ってのが今回のお話。


さて、前置きが長くなりました。まずは
https://gist.github.com/yi01/1fe1bffabdc583c09de6
にコードは公開しちゃいます。間違いを発見した方は指摘ください。(笑)


で、あまり世の中には書かれていない?話をちょっとだけ書いておくと

・Mozcのキートップ画像の要件
キートップ用のSVGなんですが、textタグは使えません。pathタグで書く必要があります。
なので、Pythonだと、svgwriteとかは使えなくて、唯一の選択肢がcairoです。

<svg>に、id="style-keyicon-main"が指定されている必要があります。これがないと、スキンを暗い色にした時に、キートップの文字が白抜きにならない不具合が発生します。

QWERTYのキー画像サイズは48x74ピクセルです。cairoはptを単位系として使っているようなので、座標系を変換しなければなりません。
でも、変換がめんどくさすぎたので、今回は成果物のxmlからptの単位がついてるものを表示しなくしてみました、それにより、意図したサイズの画像が得られます。


・Cairoの文字描画
座標系がちょっと特殊(?)です。
xBearing, yBearing, width, height, xAdvance, yAdvance = context.text_extents(text)
で文字の描画位置やサイズが取得できるわけですが、座標系が下向きY軸正方向のものなので、直感とは逆になります。

で、もうひとつ注意点としては、そのへんのサンプルにある(xBearing+width/2, yBearing+height/2)という座標は、文字領域のど真ん中(赤色の四角の重心)であって、全体的な文章のラインの中心とは異なります。これが、冒頭に書いた「ずれていて若干気持ち悪い」ということです。

↑で、赤枠ベースでの配置だと上下して見えますよね。

じゃあ、どうすればいいのか、っていうのが青枠ベースの配置。

どうやら、フォントサイズと文字のラインの高さには3/4の関係があるみたいなので
↑にあるように、64ptのフォント指定の場合は、24px(=フォントサイズの3/8)だけ下に移動してやることで、行の中心をとらえた描画となるのです。




おまけ

E/MessageQueue-JNI(31310): java.lang.IllegalArgumentException: Duplicataed sourceId is found: Binary XML file line #1710
E/MessageQueue-JNI(31310): at org.mozc.android.inputmethod.japanese.keyboard.KeyboardParser.parseKeyEntity(KeyboardParser.java:772)

みたいなエラーになった時のチェック用スクリプト

grep -r ":sourceId" kbd_*.xml | awk '{a[$2]+=1};END{for(k in a){if(a[k]>1){print k,a[k]}}}'

Ubuntu 14.04のApache2のconfigを見て「アレ?」となった話

私は、仕事で(プライベートでも?)よくGitlistっていう便利なgitビューワを使っています。
正直、自分一人だったら要らないんですが、共同作業するなら、必ず一人はいますよね。「わたしgit使えないんで(キリッ」みたいな訳の分からないことをいう人が。

まぁ事情はともかく、Gitllistは、Gitビューワとして非常にシンプルで最低限の機能はあるものなので、いろいろなサーバに建てるために

git clone https://github.com/klaussilveira/gitlist.git
cd gitlist/
curl -s http://getcomposer.org/installer | php
php composer.phar install
chmod 777 cache/
sudo a2enmod rewrite
sudo /etc/init.d/apache2 restart
くらいは、いつでもコピペできるようにしてあったりします。

環境によっては
sudo a2enmod userdir
sudo /etc/init.d/apache2 restart
も必要ですね。まぁそれくらいは誤差の範囲です。

ただ、最近になって、Ubuntu 14.04のサーバを手にしたのですが、「アレッ?」ってなりました。

最終的には
http://aoba.web-hack.org/gitlist/
にあるように、ちゃんと動いたのですが、ユーザディレクトリでRewriteがなかなか動かなくてちょっと戸惑いました。


Directory /home/*/public_html/ > AllowOverride Allとか書く場所は…

正直、これだけで躓きました。他はフィーリングで行けます。

今まで(Apache 2.2)だと、/etc/apache2/sites-available/defaultあたりに、それっぽい記載があったので、真似して
<Directory /home/*/public_html>
AllowOverride All
</Directory>

とかてきとーに書いていました。(セキュリティの云々はともかくとして…)

しかし、Apache 2.4になって、/etc/apache2/sites-available/defaultは見当たりません。
一体どこに行ったのか・・・。

じつは/etc/apache2/apache2.confにそれっぽい記載があります。
でも、本家confに書いちゃうのって微妙ですよね…。

というわけで、いろいろ試してみたところ、

/etc/apache2/conf-available/rewritable-userdir.conf
<Directory /home/*/public_html>
AllowOverride All
</Directory>
こんなかんじで1ファイル作って、
sudo a2enconf rewritable-userdir
sudo /etc/init.d/apache2 restart
ってやれば、本家のconfigをオーバーライドする感じで、設定が出来ました。(confにするかsiteにするかは悩ましいところですが…)
Apache2で「あれ?AllowOverrideの設定箇所どこ行った??ユーザディレクトリでRewrite効かないぞ?!」ってなった方は、ぜひお試しあれ。



(参考)
以下、完全に個人的な趣向の問題ですが、Gitlistをちょっとだけ手直しして使ってます。

nano src/GitList/Config.php
    public static function fromFile($file)
{
if (!file_exists($file)) {
die(sprintf('Please, create the %1$s file.', $file));
}

$data = parse_ini_file($file, true);
+ $repo = parse_ini_file($file.".repos.inc");
+ $data["git"]["repositories"] = $repo["repositories"];
$config = new static($data);
$config->validateOptions();

return $config;
}


これで、
config.ini
[git]
client = '/usr/bin/git' ; Your git executable path
default_branch = 'master' ; Default branch when HEAD is detached
;repositories[] = '/home/git/repositories/' ; Path to your repositories ★←コメントアウト
; If you wish to add more repositories, just add a new line

; WINDOWS USERS
;client = '"C:\Program Files (x86)\Git\bin\git.exe"' ; Your git executable path
;repositories[] = 'C:\Path\to\Repos\' ; Path to your repositories


config.ini.repos.inc
;QAEP
repositories[] = /home/yi01/mirror/LA.BF64.1.1-00110-8x94.0/

;AOSP
;repositories[] = /home/yi01/mirror/android-5.0.0_r2/

こうすることで、純粋なconfigと、リポジトリのメンテを別ファイルで行うことができるようになります。

Samsung SBrowserの小さな小さな工夫


ほんとうは、仕組みが解明できてから公開したかったのですが、もったいぶるメリットもないので、しょうもない内容なの承知でわかっている範囲だけ公開。

といっても、わかってるのは・・・

同じマルチタッチイベントを与えているにもかかわらず、SBrowserは中心軸がずれずに拡大縮小がされる!

以上。・・・分かり次第ちょびちょび付け足しで書いていきます…。

どんなタッチイベントを送ったか

マルチタッチと、その中心軸の遷移

点の座標をログに出してMatplotlibで可視化すると、こんなかんじで中心軸がぶれています。

そもそもAndroidってどうやってマルチタッチを解釈しているのか(書いてる途中・・・)

ScaleGestureDetectorというコンポーネントAndroidフレームワークに有ります。
マルチタッチズームの基本をちらっと図解します。

ScaleGestureDetectorのキモは3つです。
 ・[ScaleStart] 親指と人差指の間の距離をSpanといい、その距離が初期距離から16dp以上ずれるとズームを開始
 ・[ScaleBy] ズームの中心は、親指と人差指の中点(リアルタイムに更新)。倍率は、16ms前のSpanと現在のSpanの比率(リアルタイムに更新)
 ・[ScaleEnd] 指が2点じゃなくなるとズーム終了

中心の座標は、開始時のもの固定ではなくてリアルタイムにタッチの点の中心座標に更新するのがAndroid標準です。なので、冒頭で書いたとおりChromeはバカ正直にタッチの中心座標を更新するため、マルチタッチの中心軸がブレブレになって見えたりするのです。

SBrowserはこのようなタッチ中心の座標ブレブレ問題を解決しているようです。

SBrowserの工夫とは・・・(まだわからず)

オープンソースでその実装箇所を探ってる最中です。分かり次第続報をお届けします。



と、長く時間が空きましたが、結局実装箇所はわかりませんでした。
Zoomのジェスチャを判別する部分は、他の機種との差分は(ゼロではないですが)多分ない。 で、気になってSBrowser.apkを引っこ抜いて、apktool d SBrowser.apk とかなんとか探ってみようかなと思いましたが、答えっぽいものにはたどり着けませんでした。

org/chromium/content/browser/ZoomManager.smaliとかを見る限りだとAndroid標準のScaleGestureDetector使ってるし、 多分、MultiTabPinchUtilのperformPinchZoomあたりでなにかゴニョっとやってるんだろうなぁと思いつつ…
若干悔しいながら、今回はこれまで。。

Android標準のScaleGestureDetectorの動作とカスタマイズポイントが見えたくらいでよしとしておきましょう。完全に自己満足ですが。