Posts tagged ‘note taking apps’

Joplinを排除してノートアプリを完全にZimに移行したあと、うっかり その修正・改良を始めてしまい※、随分手こずったものの(2週間くらい掛かった!)かなり良くなって、概ね満足できるレベルになった。

※いろいろムカつく問題があったのだが、他にないので変更・修正や代替策などで数年間我慢して使っていた。

そして、僕の改良・改造版はノートのフォーマット(タグ)は違うし、機能・動作は かなり違うし、プログラムの構造も少し変更してオリジナルとは全く違うと言っても いいほどなので、名前を"Zimb"(Butty's modified Zim または Butty's note taking app. (Modified version of Zim))に変えた(例によって(夜中に)思い付いたw)。

オリジナルを尊重して元の名前を残し、読みも同じに なりそうなものにした。

なんかイメージの良くなさそうな南のほうの国を連想するが、まあ良しとするw

作業を始めた切っ掛け

Joplinの作業が終わり、延々と放置して来たZimのTODO(修正・改良)に着手すべきだけど、やっぱり面倒な気分でも あった(やらなくても とりあえず使えるし・・・)。ただ、以下のような ちょっと切実なことが切っ掛けになったように思う。

  • ベースを最新版※にしたくなった(V.0.74.2 → 0.75.2)。: 以前からやりたかったが、面倒なので放置していた。
    • どうせ変更(修正・改良)するなら、最新版をベースにしたほうが良いので。
    • ※作者は開発を止めた訳ではないようで、思い出したように(年に数回)更新している。ただ、機能や動作は ほとんど変わっていない感じだ。
  • Zimのノートのgitリポジトリ(バージョン管理プラグインが使う)が大きくなってしまった(500MB以上)。: Joplinの画像が多かった。ノート以外はgitに入れる必要は ないのに、馬鹿みたいに全部入れていた。
    • ある時、バックアップのサイズが大きいファイルが目に止まって気付いた。
    • 余計なファイルを削除してgitリポジトリを小さくするために、(調べて見付かった方法がうまく行かなかったので、)BFGというプログラムを使った。結構簡単で良かった。
    • 作業中に気付いたが、ZimのノートのDB(SQLite)も大きくなってしまった。: 上と同じ原因で、ご丁寧にもノートでないファイルもスキャンしてDBに登録・更新していた。
      • それでノートのエクスポートやプログラムの終了が遅くなって居た(多数(1万個以上)のファイルのインデックス処理をするため)。
  • ZimのPage indexプラグインで鬱陶しいURL(link placeholder)を消したい。
    • URLをノートにペーストすると、左サイドバーのノート一覧に それ由来らしき(エンコード? ダイジェスト?: 分からないので部分的に隠した)記号の名前のページが出て増えて本当のノート名が見えにくくなって、すごく不便だった。
    • 以前削除しても復活したので、諦めていた。

ベースを最新版に

手間は掛かったが、意外にすんなりできた(最新版までの変更が少ないということ)。比較とマージをGUIで手軽にしたかったので※、Linuxで使えるものを探したら いくつかあったもののどれも満足できなかったが、一番良かったMeldにした。

※昔はWinMergeを使ったのを思い出す。

Zimの修正内容

主なものを以下に列挙する。

  • 2重表示の問題(ページの再描画が おかしいことがある)
    • 現象
      • 大きいノートの後半辺りに行を挿入したりすると、その前後の行が微妙に ずれて2重に表示されることがある。
      • 一旦 別のアプリのウインドウをアクティブにしてZimに戻ると直る。 → 今まではそれで しのいでいた。
        • ↑のためにキャプチャを取るのが難しく、提示できない。
    • 原因: プログラムの処理が不適切(ページ描画処理手順が悪い(推測)のと その回避のための"HACK"処理(下を参照)が良くない)。
    • 参考
      • これを解決できたので、プログラム中の謎の処理"_hack_on_inserted_tree()"(zim/gui/pageview/__init__.py, 以下、"HACK")を不要に出来た。
      • この問題と下のノート切り替え時のカーソル位置の復元は関連している。
        • カーソル位置の復元などのためにHACKがあるのだが、その処理が不適切なために2重表示が起こっていた。
        • そもそも、ZimのGTKの使い方が今一つなためにページ描画が遅くなり、HACKがないとスクロールできない(→ カーソル位置が復元できない)問題が起こっていたと推測する。
      • (9/18 14:59) LibreOffice Calcでも起こった(以前からあったのを忘れて居た)ので、GTK全般で起こりうる問題のようだ。ただ、いつも・どのアプリでも起こる訳でないので、起こりやすい条件(描画の仕方? グラフィックデバイス関係?)があるのだろう。
    • 対処: ページ描画手順を真っ当と思われるものに変更し、HACKを不要にした。 (詳細は実装メモを参照)
  • (2重表示の問題が起こらないようにHACKを無効にした構成では、)ノート切り替え時にカーソル位置が復元できない。
    • 現象: 上のHACKを有効にしないと、ノート切り替え時にカーソル位置が復元できない。
      • ただ、HACKが有効でも、大きいノートでは復元できないことが多い。
    • 原因: プログラムの処理が不適切(ページ描画処理手順が悪い(推測))
    • 対処: ページ描画手順の変更。
  • 長い行を綺麗にラップ(折り返し)できず、横スクロールバーが出ることがある。
    • 現象: 長い行は適切にラップするはずだが、横スクロールバーが出るうえにページが左にずれて行の先頭が隠れてしまうことがある。
      • なぜかHomeキーではカーソルを戻せないので、すぐには行の先頭が見えず大変不便。
    • 原因: 不明。
      • Zimの問題なのかGTKの(設定の)問題※なのか不明
        • ※他のアプリでも似たような現象が起こることがある。
    • 暫定対処: ページのマージン(特に右マージン)の調整
      • かなり大き目(例: ページ幅約800pxに対し、50px)に右マージンを取った。
      • 試行錯誤のため、マージンなどを設定で容易に調整できるようにした。
    • 参考: これでもスクロールバーが出ることがあるので、完全には対処できていない。
      • スクロールバーが出るのは、大きな画像がある他にVerbatim(文字を そのまま出す書式)の長いブロックが関係していそうだ。あと、日本語は単語の区切りの空白がないので、そもそもラップしにくいのかも知れない。
      • このブログの表示を見て思ったが、単語間(駄目な時は文字)で切るのに加えて、字の間隔を微妙に伸縮させて調整できると随分良くなりそうだが、GTKでできるのだろうか?
        • ただ、それも破綻する(日本語の文字が飛び石になってしまう)ことがあるので良し悪しだ。。。
  • Zimアプリ(GUIプログラム)を閉じて終了させてもプロセスが残って居ることがある。
    • 現象: Zimのウインドウを閉じてもプロセスが終了しない。
      • 修正・改良後の確認時にはkillコマンドで強制終了する必要があって(そうしないと残ったプロセスが動くので、変更点の確認ができない)、大変不便だった。
    • 原因: バックグラウンドで実行しているインデックス処理が終わらない。 (上の「切っ掛け」を参照)
      • ノートのディレクトリにあるすべてのファイル(1万個以上)をインデックスするため、時間が掛かっていた。
    • 対処: ノートのファイルだけをインデックスするようにした。
      • インデックス対象と除外するファイル・ディレクトリ名のパターン(正規表現)や種類(sym-linkを除外するか)を設定で指定できるようにした。

Zimの改良内容

主なものを以下に列挙する。

  • タグの中に使えない文字がある。: 例: VERBATIM(文字をそのまま出す書式)なのに ' が使えない。
    • VERBATIMは、タグが '' で本来の文と競合するようなので、書式のタグを変更した。
      • Zimを使い始めた時の変更(下も参照)と同様に、タグの文字列を、本来の文と競合することが少なそうなものにした。また、タグは2文字構成だが、開きと閉じそれぞれの先頭と最後の文字を、一般には使わない「変な文字」にした。
        • 参考: Zimを使い始めた時に、かなり不便だったので(その他の"__"の件を参照)次のタグを変更した。: EMPHASIS(斜体), MARK(下線)
    • 同様に、次のタグの書式を変えた。: VERBATIM, STRONG(太字), STRIKE(取り消し), SUBSCRIPT(下付き), SUPERSCRIPT(上付き)
    • タグを変更すると以前のノートを修正(タグを変換)する必要がある※が、読み込みは新旧両方に対応し、書き込みは新しい書式にすることで、変換を不要(自動変換)にした。
      • ※それで追加のタグ変更を保留していたが、今回は少しスキルが上がって上のような うまい方法ができた。
  • 埋め込み画像サイズの自動調整
    • 画像をインデントした場合でもページ幅を超えないように、自動で縮小するようにした。: 上述の横スクロールバーをなるべく出さないため。
      • デフォルトや最小サイズは設定で変更できるようにした。
      • そのため、画像が多いノートの描画が遅い。
        • → 思い付きだが、ノートをビューに表示する時に初めて、実際に表示される画像を読み込めば良い気がする(webのlazy loadingのイメージ)。ただ、それがGTKで可能なのかは不明だ。
          • 例えば、TextBufferの中にコールバックを設定とかできるのだろうか? あとは本当に そういう属性があるか。: まあ、忘れたほうが良いw
  • URLをペーストした時、自動でクリッカブルリンクにしないようにした。
    • 上述のURL由来の変なノートができるのを防ぐため。
    • 自動でリンクになるのは便利だが、不意にクリックすると勝手にブラウザでアクセスするため、神経を遣って却って不便なので無効にした。
      • 手動操作でリンクにすることは できるので、問題ない。
  • ウインドウなどの設定ファイルなどの位置を変えた。
    • オリジナルではノートのインデックスのDBとともにキャッシュディレクトリ(~/.cache/zim)に入っているが、キャッシュは「いつ消しても大きな問題は起こらない」と思わせて適切でないので、(いい場所が思いつかなかったものの)~/.local/share/zimにした。
      • 本来はウインドウなどの設定は~/.configが良いが、なぜかDBも一緒に保存されて分割が容易でないので そうした。
  • MDでのエクスポート時の上下付き書式を変更した。
    • これまではJoplinが対応している形式(^, ~)だったが、スマフォのビューアをObsidianにしたのでGFMの形式(HTML, <sup>, <sub>)で出すようにした。
  • キャレットを点滅しないようにした。: イライラする(までは行かないが、「うるさい」)ので。
    • 点滅を設定する方法を調べたが、プログラムからはできないようなので、GTKの設定ファイル(~/.config/gtk-3.0/settings.ini)に以下のように書いた。※
[Settings]
gtk-cursor-blink=0
      • ※そのため、他のアプリも同じ設定になるが、そもそも点滅が嫌なので問題はない。
    • それに伴い、キャレットの色や太さを調整した
      • キャレットが点滅せず細いと、黒はもちろん 色が付いていても、ページ切り替え後に どこにあるか分からないことがあるため。
      • また、太過ぎると文字の一部を隠してしまうことがあるので、太さ(アスペクト比)を微調整した。
        • 太さは今一つ調整の自由度(ステップ)が少ない感じだ。
        • また、アスペクト比の設定のため、行が高い場合(例: 画像のある行)はキャレットが巨大になってしまう。この回避方法は まだ分からない。
    • 変更する方法を調べたが、プログラムからはできないようなので、GTKのCSSファイル(~/.config/gtk-3.0/gtk.css)に以下のように書いた。※
* {
  caret-color: #812a2f;
  -GtkWidget-cursor-aspect-ratio: 0.12;
}
      • ※キャレットの点滅と同様に他のアプリも同じ設定になるが、このブログのヘッダの色に近く、悪くない感じの色なので大きな問題はない。

実装メモなど

A. 2重表示問題の対処・描画処理手順の改良

僕はGTKに詳しくないが、Zimのプログラムを調べて分かったことと推測したことの概略を書く。

  • オリジナルのZimは、以下の順序でページ(ノート)を描画している。
    1. ページ(ノート)全体(ノートのテキストと埋め込まれている画像全部)を読み込んで解釈し、バッファ(TextBuffer)に描画オブジェクトを作り上げる。
    2. 出来上がったバッファをビュー(TextView)に登録する。 → GTKの描画処理が始まる(全体を一気に描く)。
    3. [HACK処理]
      1. GTKの処理がアイドルになるまで待つ(GLib.idle_add(hack関数))。
      2. hack関数: 指定時間待ってからスクロールする(GLib.timeout_add(タイムアウト, スクロール関数))。
        • 本来はアイドルになるまで待てば充分なはずだが、うまく行かなかったのか、指定時間待ってからスクロールしている。
          • 実際、タイムアウトが短いと充分にスクロールしない。
      3. スクロール関数: カーソル位置を復元するため、ビューをスクロールさせる。
  • GTKで一気に表示処理をするため、どういう理由かは分からないが、上述のスクロールが行われない問題が起こる。
  • それを回避するためにHACK処理をしているのだろうが、2重表示の問題が起こる。
    • 調べた限りでは、(理解不能なものの)HACK処理自体は悪くないが、複数の(余計な)ところから実行するのが良くないようだ。

ただ、他のアプリで 上のような問題(スクロールしない, 2重表示)が起こっているのを見たことがないし、検索しても出て来なかった。※

※スクロールが起こらない問題に関しては あったが、Zimは ちゃんとスクロールできるはずの方法で実行していた。

そこで、一気に描画するのが良くないと考え、順次描画するように、以下のような順序にした。

  1. 空のバッファ(TextBuffer)をビュー(TextView)に登録する。
  2. ページ(ノート)を読み込み、順次バッファ(TextBuffer)に描画オブジェクトを作り上げる。 → GTKは順次描画処理を するはず。
  3. GTKの処理がアイドルになるまで待つ(GLib.idle_add(スクロール関数, カーソル位置))。
    • これはオリジナルのHACK処理にヒントを得た(上を参照)。
  4. スクロール関数: カーソル位置を復元するため、ビューをスクロールさせる。

駄目元でやったのだが、意外にうまく行った。まだ1日くらいしか試していないが、今までに1度2重表示が起こった(これが気になるが・・・)ものの、カーソル位置は常に復帰できて かなり改善できたし、謎のHACK処理が不要になった。

ただ、変更前はページが順次描画される(例: ノートの先頭から描画されるのが見える)ようになると思って居たが、そうではなく、どういう訳かビューは ずっと空のままで、最後に一気に全体(ビューのうち見える部分)が表示される。

調べていないが、もしかすると、表示に関する もう一個のPageViewというwidget(VBox)とTextViewの関係があるのかも知れない。上述のTextViewとTextBufferのように、最後にTextViewをPageViewに登録しているのだろうか。 ← プログラムを見てみたが、そうではないようだ。TextViewはPageViewの生成時に設定している。

(21:55) 最後に一気に表示されるのが気になってプログラムをチェックしたら想定と違っていて、上の手順の1の空のバッファ(TextBuffer)をビュー(TextView)に登録していなかった。そのために一気に表示されたようだ。

ということは、最初の(抜けのあった)修正でも うまく行ったポイントは何だったのか分からなくなった。: 結局、オリジナルのHACK処理と その実行の仕方が悪かった(「素直」でなかった?)のか。: また あとで考えたい。

それで上の手順になるように修正したら、画像の多いノートでの描画開始までの待ち時間は相変わらず長いものの、描画途中の状態が ちょっと見えてから復元されるべきカーソル位置にスクロールするようになり、想定に合うようになった。

この辺りには まだバグがありそうだ・・・

B. 特定のキーが取れない

動作確認をしていて気付いたのだが、なぜかショートカットのCtrl+5がZimに届かなかった(妙なことに、Ctrl+4まではOKだった)。更に、Alt(Shiftなし)は全滅だった。いろいろ調べたら、FcitxがCtrl+5を取っていた。。。※ AltもFcitxが怪しい(どうしても解決できなかった)。

※なんで そういうテキトーな割り当てをするか不明だが、まあ、そういうプログラムなので仕方ない。他にもムカつくことはあるが、他にないので我慢+可能な修正をして使って居る。

(9/14 19:15) 取れないキーは他にもあった。: Ctrl+0やCtrl+. が取れないことに気付いた。前者は(僕がPythonとGTKに詳しくないため、)プログラムの誤りなのか他に原因があるのか分からないが、プログラムを修正して使えるようにした。 ← その後、また駄目になって居た。全く謎だ。 (19:44) ← その後、Zimを起動するディレクトリによって動作が変わることが分かった。 (20:39)

Zimの開発ディレクトリで起動した場合、その下位に そのキーの機能(Remove heading)を含むメニューバー定義ファイル(menubar.xml)が あってキーを取得するが、そうでないディレクトリからは古い版の定義ファイルしか参照できず、キーが無効になった(この機能は最新版で追加されたようだ)。

定義ファイルにはキー割り当ては書いてないけど なぜか関係しているので、大変分かりにくい。また、新しい定義ファイルでは下の変更は不要だった。

具体的には、下のショートカットキーの定義らしき行で、オリジナルには"accelerator="がないのだが、それを他に合わせて入れたら取れるようになった。ただ、別のキーで それがないものも動いているので、何だか分からない。

@action(_('_Remove Heading'), accelerator='<Primary>7', menuhints='edit')

後者は ひどく、FcitxだけでなくGTKも取っていた。GTKでは絵文字一覧(Emoji chooser)が出てしまう。調べても、設定で出ないようにする方法が分からない(プログラムでの方法は あったが、これは全体的に無効に変更したい)・・・ 杜撰なソフトは多いが、GTKは ひどい。使うための資料も機能も不足している。

残件

まだ結構あり、以下の順序で対応したいと思う(が、疲れたし、充分問題なく使えて居るので面倒だ・・・ → また数年後?)。"[Fix]"は修正、その他は改良である。

  1. ノートのsuffixの変更
    • 今は なぜか"txt"で、普通のテキストファイルと区別できず不便なので変えたい。
  2. 書式タグと本来の文を競合しにくくする(残り)
    • 次が残って居る。: IMAGE(埋め込み画像), LINK(リンク・埋め込みファイル), VERBATIM_BLOCK(複数行のVerbatim), OBJECT(不明), HEADING(見出し), TABLE(テーブル), LINE(水平線)
      • 箇条書きの*と同様に、そのままでも良さそうなものがあるので、良く考える必要がある。
  3. クリップボードをplain textとしてペーストする機能の追加, ペーストするフォーマットの順位設定
    • ([Fix] ファイルマネージャ(Thunar)からのファイルパスのペーストがリンクになる。)
    • 今はxselコマンドを使った外部プログラムで実現している。
  4. 日付の挿入(Ctrl+D)時、カーソル(上下)で書式を選べるようにする。
    • 今はマウスでしか選択できない。
  5. [Fix] 日英混在の場合(?)、ダブルクリックでの単語の選択が おかしいことがある。
    • GTKの問題・設定かも知れない。
  6. [Fix] カーソル(キャレット)の見栄え
    • もう少しなんとかできる?
  7. [Fix] 書式など(例: 箇条書き)のプルダウンメニューの展開が なぜか遅い。
  8. ツールバーの箇条書き, 番号付きリスト(, チェックボックス, 見出し)の各要素を独立させて横に並べる。
    • 煩雑になりそうなので、要検討。

また、以下は対応困難か実害が少ないので、非対応か保留にしようと思っている。

  • 長い行を完全にはラップできず、横スクロールバーが出ることがある。: 頻繁に起こるなら対処する。
  • ノート中に画像が多いとメモリを食うのは仕方ないが、適宜解放できるとうれしい。
    • 動作を見ると解放していない訳ではないので、Pythonのメモリ管理の問題か、Pythonが解放してもOSが「引き取っていない」のかも知れない(調べたら、良くあるようだ)。
  • アプリ終了時に全部の子プロセスを止める。

その他

ここまで読めば分かると思うが、オリジナルのZimは使いものにならないと断言できる(「敢えて言おう、〇〇であると!」レベル)。良く作者は気付かないものだ。そういうのは気にしない人なのか、自分では余り使ってないのか??: ベースが使えるものなので怒りはしないが、プログラムは なかなか几帳面に書かれているだけに理解不能だ。

  • 例えば、ZimはPythonで書かれているから、作者は"__init__"のような文字列をZimのノートにペーストしそうだが、ペーストの直後にVerbatimの書式に設定しない限り、下線の書式("init")に変換されてしまう。
    • 同様に、Pythonのdocstring('''...''')をペーストしたら、コードブロックに変換されてしまう。
  • 結局、普通に書いて そのままだと情報が変わってしまい(上の例では__'''が失われる)、ノートアプリとしては失格だ。
    • そういうのを書くたびに、漏れなくコードの書式に設定しているのだろうか。気にしないのだろうか? それでも、いくらなんでも__は不便だと思う。

感覚や思想の違いだと思うが、Zimは余計(邪魔)な機能が多い割に、基本的なことが欠けている。だから、随分可能性があるのにユーザーが増えないのではないか。

 

書いたあとでの追加

A. メモリ使用量についての調査・検討 (9/13 15:36)

上に書いたように、Zimがノート中の画像が多いとメモリを食い、しかも増え続けるのが気に入らなかったので少し調べてみた。すると、いろいろなことが分かった。

まず、Zimには意外にもページキャッシュがあることが分かった。どうやらページの表示イメージ(≒ TextBuffer)をそのまま格納しているようで、ページを2回目以降に開く場合は すごく高速になる。※ それは良いが、ページがキャッシュに残って居るうちはメモリ使用量は減らない。しかも、どうやら無限のページ数をキャッシュするようなので、メモリ使用量が増え続けるのが納得できた。

※今までは、僕がZimを使い始めた時にした改造が障害になって高速にならないことが多かった感じだが、この調査のために それを無効にしたら、カイカン的な速さになった。: 画像が多いノートでも一瞬で出る! (その代わり、メモリ・・・)

そこで、キャッシュのエントリ数(保持するページ数)を制限してみた(例: 10)。数が上限に達した場合には、(とりあえず、)最も過去に参照したものを削除するようにした(LRU)。が、それでも減らない感じだった。

更に調べると、ZimはPythonで書かれているため、基本的には、使われなくなった(= 他から参照さなくなった)メモリはGC(ガベージコレクション)で自動的に解放されるが、相互・循環参照※されていると解放できないことがあるそうだ。 (→ 参照: 大雑把にしか読んでないが、随分参考になった。)

※相互・循環参照の例を以下に書く。

    • 相互参照: 2つ(以上)のオブジェクトの間で参照し合っている。: A → B → A
      • 参照が片方向だけなら問題ない。
    • 循環参照: 自分で自分を参照している。: A ⇔ A

プログラムを調べてみると、確かに、テキストバッファ(TextBufferクラス)には他のクラス(例: その上位のTextView)のオフジェクトと相互に参照し合っているメンバがあった。そのためにページを切り替えても解放されない可能性がある。

相互参照はオリジナルのプログラムでもあったが、僕が追加した部分が多かった。上のようなことを知らずに、「ちょっと」上位クラスのメンバを参照したくて、テキトーに追加したためである。

そこで、とりあえず、ページをキャッシュから削除する時には もう誰も参照しない時だろうから参照関係を切っても良い(プログラムの動作が破綻しない)と考え、そのような処理※を追加したところ、概ね期待どおりの動作となった。

※具体的には、A → B → Aという参照関係がある場合、BのメンバのA(へのポインタ)にNoneを代入してB → Aを切った。

残念ながらメモリ使用量が減ることはないが、増え続けることもない。: キャッシュ内のノートのサイズの合計が それまでの最大値以内である限りは増えることがないので、プログラム(Python)内でメモリをやり繰り(再利用)できていると考えられる。

減らない理由を想像すると、(上述のように、)Pythonが解放してもOSが受け取らない のではないかと思うが、他に、まだ参照を切るのが甘い可能性もある。

というのは、どこで参照しているのか分からないが、キャッシュから削除する時の参照カウントが70近いからだ。どうしてそんなに参照が増えるのかは謎である。

(9/14 12:39) 参照カウントが随分多いのが気になったので参照元を調べたところ、ページの参照の大半はファイルタイプの定義(例: 'image/png')からのようだった。今回はプログラムは見ていないため、なぜそんなものが他のオブジェクトを参照しているかは不明だが、そういう実態だ。そして、メモリ解放の障害となる相互参照は、上述の「僕が追加した部分」だった。

(9/14 16:33) その後 更に試したところ、キャッシュから古いエントリ(ページ)を削除したあとで強制的にGCを実行すれば、キャッシュの合計サイズが小さくなる場合にメモリ量が減ることが分かった。だから、僕の修正が正しいこととOSは解放されたメモリを回収していることが分かった。

なお、必ずしもGCしなくても良い(GCはPythonに任せる)はずだが、今一つタイミングが遅い感じなので、(気分・好みの問題で)するようにした。

次に、推測ではあるが、画像が多いとメモリを食う理由も分かった。使って居るグラフィック処理系のGTKは、画像をGdkPixbuf(以下、Pixbuf)という形式で保持する。そして、(悪い予想が当たり、)Pixbufは非圧縮のフォーマットしかないため、JPEGやPNGの画像を表示させる場合でも展開するためにメモリ使用量が増大する(BMPみたいな感じ)。そのため、添付画像が多いノートを表示するとメモリ使用量が増大するのだ。

試しに、画像の多いノート※で検討してみた。

※このノートは定期的に同じグラフの画像をキャプチャして貼り付けているので、すべての画像のサイズがほとんど同じで、計算には都合が良い。

  • ノート内の埋め込み画像のサイズ: 約700x450 650x390px
    • → 上のサイズのPixbufの予想メモリ量: 923 990kB/画像 (700x450x3 650x390x4)
  • そのノートを読み込んだ(表示している)時のZimのメモリ使用量の増分: 約68MB
  • ノート内の埋め込み画像の数: 73
    • → 1画像当たりのメモリ量: 約950kB/画像 (68x1024/73)
      • ※このノートのテキストは約14 8.4kBと小さいので、ここでは無視した。

注: その後、実際のPixbufオブジェクトにはアルファチャネルがあって4チャネルであることと、実際の画像サイズは約650x390pix、テキストサイズが約8.4kBであることが分かったので修正した。 (9/16 11:00) ← どうしてサイズが違ったのか考えたら、元の画像は修正前のサイズだが、表示時に自動でリサイズしているためのようだ。 (9/16 13:29)

Pixbufの仕様から推算した1画像当たりのサイズとメモリ使用量の増分からの1画像当たりのサイズが合ったので、無駄にメモリ使用量が増大しているのでは なさそうなことが分かった。

(9/16 11:10) なお、実際のプログラムで画像のデータサイズを求めたところ、上と合っていた。: Pixbuf.get_byte_length()の値と、get_width()などの画像パラメタから上の方法で計算した画像サイズが一致した。

これを改善するには、TextBuffer(あるいは他のGTKの要素)で画像を圧縮したまま扱えれば(表示・コピー・ペースト・移動など)良いが、少し調べた限りでは できなさそうだ。ブラウザのように表示だけならともかく、編集までできるようにするのは難しい気がする。

ブラウザが どうやっているか分からないが、やっぱりPixbuf(あるいは同様の非圧縮フォーマット)の気がする。だから、あんなにメモリを食う(もちろん、これだけではない)のかも知れない。

(9/16 11:27) 他に、画像を読み込む時にアルファチャネルを削除すればデータサイズは3/4になるだろうが、根本的でない気がする。でも、ちょっとやってみたい。

B. 画像からのアルファチャネルの削除 (9/18 12:40)

苦心惨憺して できた。GTKには なぜかアルファチャネルを削除する処理(API)は なさそうなので、作った。処理自体は簡単なのだが(それでも分からないことが多かったので、楽ではなかった)、Pythonで書いたら遅過ぎた(元々の5倍くらい時間が掛かる)。

処理の概要: Pixbuf(アルファあり) → Bytes → アルファチャネル((インデックス%4)==3)を削除※ → Bytearray → Pixbuf(アルファなし)

※おもしろいことに、調べて見付かった凝ったデータ抽出方法([]内にループを書くようなやつ)より、普通に愚直にループ+配列のslice → extend()で書いたほうが速かった。[]内のループをコンパイルできるなら、速くなるのだろう。

まあ、元々心配していたが、いくらPythonが速くても こういう処理には無理がある。そこで、ネイティブで書かれたライブラリを使うことにし、元々Zimで使われていたので思い出した、PILというライブラリのconvert()という関数を使った。PILも、癖があったり資料が今一つ親切でないので苦労した。

処理の概要: Pixbuf(アルファあり) → Bytes → PILのImage("RGBA") → convert("RGB") → Bytearray → Pixbuf(アルファなし)

GTK→PIL(アルファ削除)→GTKとデータ変換が多くなったが、元々からの速度低下は ほとんどない。ページ読み込み(表示)時間は元々と変わらないのに速くなったように感じる(キャッシュされているページが一瞬で出る)のは、気のせいとかプラシボ効果だろうか。画像のサイズが小さいとかアルファがないために処理が軽くなった可能性もあるが、数値※は同じである。

※数値が変わらないのはキャッシュされていないページを最初に表示する時のことで、キャッシュされているページの表示は本当に速いのかも知れない。

メモリ量は、内部的(ページサイズ)には計算どおり3/4になったものの、OS(Linux)側では従来どおり多目に出る。まあ、仕方ないのだろう。: Pythonがプールして解放していないとか、解放してもLinuxが引き取らないなどかと想像している。

 

余談: Zimへの寄付について

今までずっと、「ちゃんと使う・使えるようになったら寄付しよう」※と思いつつも迷って居たが、止めた。

※そもそも、(良くあることだが、)PayPalでは日本から寄付できないし、PayPal以外の方法は示されていない。

本文に書いたように、オリジナルのままでは使いものにならないので寄付しないことにしたが、ベース(骨組み)としては随分役に立っており、良くあれだけの内容・量を作ったものだと感心しているので、きっぱり切り捨てられずに今一つモヤモヤしていた。

それで、僕の修正・改良のいくつか(例えば上述のHACKを不要にする方法)をフォーラムに投稿すれば充分に寄付の代わりになりそうだと思い付いたので、もう少し試用して改良が問題ないことが分かったら することにした。*

*が、今までの経験から、投稿しても大抵は無視とか放置になるのが分かっているので、最初は手を掛けないようにしたい。作者が興味を示したら、詳しく教えることにしよう。でも、詳しく書いたら放置や却下もあるので、そもそも手を掛けないようにしよう。

 

PS. Zimには全く関係ないが、フォーラムやユーザー対応で今までで一番良かった(親切・真摯だった)のはMusicBeeのSteven(うろ覚え)だったかも知れないと、今思い出した。だから僕は翻訳を したくなったのかも知れない。彼は今もMusicBeeの開発を続けているのだろうか?

 

(9/13 10:11 誤字を修正。: 「解放」と「開放」は難しい・・・, 15:36 「メモリ使用量についての検討」を追加, 19:15, 19:44, 20:39 少し修正・加筆, キーが取れない件に追加; 9/16 11:27 PixmapはPixbufの誤りだったので修正, ページサイズの推算でのパラメータを修正, 画像のデータサイズについてなどを追加; 9/18 12:40 画像からアルファチャネルを削除する処理について追加, 14:59 2重表示について追記)

  •  0
  •  1
Keys: , , , , , ,

気付いたら前回から1か月も経っていた・・・ 億劫で本格的な着手は先週だったが、やっぱり手間が掛かって長引いた。約千個のJoplinのノート(画像などを含めたデータ量は約1GB)をZimに移した。

時間と手間は掛かったけど大したことはしておらず、移行スクリプトの作成・既存スクリプトへの機能追加・デバッグ・動作確認程度だ。以下に概要を書く。

ニッチな作業で普遍性がないうえに(手間の関係で)概要しか書けないので他の方の参考には ならないが、自分の整理として書く(詳細が知りたい方はコメントで質問されたい)。

Joplin→Zimへの移行処理

  1. Joplin→Zimの変換 (xfr-jop2zim.sh)
    1. 指定したJoplinのノート/ノートブック中のノートに対して次を行う。
    2. 対象のノートがZimに変換済みでない場合、そのノートをZimに変換する。
  2. Joplinのリソース(画像など)のZimへの取り込み (att-jop-rsrc.sh)
    1. 指定したZimのノート/ディレクトリ中のノートに対して次を行う。
    2. 対象のノートがJoplinのリソースを参照している場合、そのノート中のJoplinのリソースをZimのリソース(添付ファイル)にする。

1, 2どちらの処理用のスクリプトも これっきり使わない(はずの)ものだが、半ば無駄に高機能化した。例えば、Joplinのリソースを参照しているZimのノートの一覧を出す機能や、ノートブック内の全ノートだけでなく、子ノートブックに対しても再帰的に処理する機能などがある。

そうやって苦労したにも関わらず、もう、処理が2段階だったこと(スクリプトが2個あったこと)を忘れて居た・・・ (まあ、「これっきり使わないもの」ってのは そういうものだ。)

新たにプログラム(スクリプト)を作るのが面倒だし、誤りが多くなりそうなので、既存のもの(機能追加した)を流用・組み合わせた。

書いたあとで気付いたが、上の処理は「流用・組み合わせた」と書いたように、どちらも今まで または前回出来ていたもので、今回は それらを組み合わせただけだ。では何に苦労したかと思い起こすと、ノートの中には特殊なパターンがあって、想定する動作にならない場合があることと、多くのノートに対して 漏れなく2段階の処理をする(しかも結果の確認と処理の修正もする)という純粋な手間だった。

例えば、そもそもJoplinでもZimでも「エクスポート」するだけではリソースのファイルはコピーされず、そのままスマフォに送っても画像などが表示できないことがあるのでコピーし、ノート内のリソースの指定を そのコピーしたものに書き換える。その処理で、リソースの指定(≒ ディレクトリ)には いろいろな種類があり、それらを完全に把握して対応するのが難しいために上記の「特殊なパターン」が多発した。

それらの概要を以下に示す(以前にも書いた気がするが、変更もあるので再度書く)。

移行処理で使って居る処理の概要

  1. Joplin(MD) → Zimにエクスポート (jop2zim.sh): 元々使っていたものを若干修正した。
    • 基本的にはJoplinのMDをpandocでZimのフォーマットに変換すれば良いが、pandocだけでは うまく行かないので、以下のようにした。
      1. Joplinからノート(MD)を取得
        • Joplinでエクスポートされるものは不便なので、cliのcatでノートを取得している。
      2. 前処理
        • Zimに変換後では無理な処理をする。
        • Joplinのノートブック→Zimのディレクトリ変換, ノート・ノートブック中の特殊文字の対応, リソースディレクトリ, リソース(画像など)指定, 書式(改行他)の修正・調整, pandocの誤り対応
      3. MD→Zim変換 (pandocを使用)
      4. 後処理
        • 書式(改行, 見出しの下線他)の修正・調整, 僕が変更したZimタグへの対応
      5. 追加情報ファイルの作成
        • Joplinのノート・ノートブック情報, エクスポートした日時, 自動エクスポート(Zim→MD)の可否※などを格納する。
          • ※例えばMDはスマフォに送るので全部のノートを変換する必要はなく(全部送るとデータ量が増大する以外に、同期が頻繁になって電池消費が増える)、その選択に使って居る。
            • 今回は、全部を自動エクスポート不可にし、スマフォに送るものだけ設定変更することにした。
      6. Joplinのノートにエクスポート済みのタグを付ける。 (処理の繰り返しを防ぐため)
    • 備考
      • リソースはJoplinのディレクトリにあるものを参照する。
      • Joplinのcliが不便なので、sqlite3でJoplinのDBにアクセスしてノートやノートブックの情報を取得している。
  2. Joplinのリソース(画像など)をZimのリソースにする。 (zim2md.sh -AJI)
    • 下のZim→MDの処理と共通部分が多いので、機能追加した。処理内容は下を参照のこと。
  3. Zim → MDにエクスポート(主にスマフォでの閲覧用)時にZimのリソースをMDのリソースにする。 (zim2md.sh): 元々Zim→Joplinにエクスポートするスクリプト(zim2jop.sh)だったものを改造・機能追加した。
    • MD変換はZimのMDエクスポート機能だけでは うまく行かないので、以下のようにした。
      1. 追加情報ファイル(上述)のサポート
        • 例: 自動エクスポート不可の場合は処理しない。
      2. Zimのノートを一時ノートにコピーして前処理
        • MD変換後では無理な処理をする。
        • MD書式(水平線, 箇条書きのインデント, 引用, コードブロックなど)の修正・調整
        • リソース(画像など)の抽出・存在チェックも行う。
      3. Zimで一時ノートをMDにエクスポート
      4. MDを後処理
        • ノートの題の復元(追加), リソース指定(ディレクトリ)の修正
      5. MD(またはZim)にZim・Joplinのリソースをコピー
        • MDと同じディレクトリにリソースディレクトリを作ってコピーする。
        • Zimの埋め込みリソース(MDの"[alt](URL)"(画像でないもの, 先頭の!なし)に対応するもの)はPC内の任意のファイルが指定されるので、MDにコピーするサイズを制限している。
          • 全くコピーしないことも考えたが、多少でもスマフォで見られれば便利と考えた。
      6. MD(またはZimのノート)内のリソース指定(パス)を書き換え
        • Joplinのリソース
        • Zimのリソース

その他の作業

  • (延々と)準備・検討・確認, プログラム作成・修正, 動作確認, デバッグ・・・
  • ノートの記述、ファイル名、ディレクトリ構造などの修正・調整(修正できない/面倒な/1回しか起こらず、以降も使わない場合)
    • 手抜きだが、もう使わないプログラムを手間を掛けて直すのは馬鹿らしいので。
  • Zim内のJoplinのリソース(sym-linkで参照)の無効化 (何らかの手違いで参照されたらエラーで分かるように)
  • MD内のJoplinのリソースの削除(不要になったので)

その他

  • 元々Evernoteだったノートは、変換を繰り返した(Evernote→Joplin→Zim)ためにフォーマット(特に改行、水平線、箇条書き)が ひどいことになっているが、文章は損なわれていないはずなので、良しとした。
    • 途中でDropbox Paperを使ったり、LinuxではNixnoteを使っていたこともあって、かなり ひどいものがある。下の画像抜けは その関係があるかも知れない。
  • Evernoteから移行したものでは画像が なくなっていることが結構あり、自分で処理したとは言え、汎用性のないフォーマット・サービスは良くないと思った。
  • スクリプト(特にzim2md.sh)は場当たり的な修正が多くなってしまい、肥大化・複雑化して自分でも全容・詳細が把握できなくなってしまったが、作り直すのは大変なので仕方ない? (どこかの銀行みたいだ・・・)
    • 「*すれば(手軽に)できそうだ」みたいな始め方が悪かったのは認めるが、そうでもないと始まらなかった。
  • 当然ながら、もうJoplinのDB(約170MB)を変更しなくなったので、自動バックアップでのデータ量が減った。変更があると100MB以上(PC全体での量、以下同)だったのが、数十MB(50MB以下の場合も多い)になった。
  • 今後、Zimから他に移る可能性があるかも知れないが、その時は汎用的なMDに変換できるので楽そうだ(実際には やっぱり大変だろうw)。
  • 上で「MDは汎用的」と書いたが、実際には いろいろな種類(流派)があるうえに機能が今ひとつだ。例えば、上・下付きの書式が統一されていない(というか、ない!)。外にも少し(ものすごくではない: 逆に、ものすごい機能はある)凝ったことをしようとすると、非互換かHTMLや外部機能に頼る羽目になって、「何考えてるんだ?」と思う。それが僕がZimを使って居る理由の一つだ。
    • まあ、ZimはZimで欠点(問題点/不具合)は いろいろある・・・ が、機能面では僕には最適・必要充分に近い。

 

PS. 以前からのTODOが一つ消化できた。が、次にはゴミ箱タイヤ交換PC・サーバのOSなどの更新が控えている。そう言えばスマフォの交換(買い替え)もあったな。依然として どれも面倒だw

PS2. 本文に書いた「特殊なパターン」に苦労したことで思ったが、僕でさえ そういうことを想定して少しずつ試しに処理して確認・修正しながら進めたのに、ある国の何とかカードの保険証は一気に国全体で始めてしまい、案の定、問題が多発している。「(いいシステムなので)問題は ないと思う(分からん)が、何かあったら現場で頑張れ」のスタンスかと思われるが、そういうのはプロとして恥ずかしい限りだ。まあ、大層な名前や肩書だけど、頭でっかち・口ばっかりでプロじゃないんだろう。

詭弁的な言い訳に、「発生率は極小なので、大きな問題ではない」とかいう、いかにも納得しそうなものがあるが、そういうレアな問題にもシステムの正当性・安全性に疑問を生じさせたり危険性を示すものがある可能性があるので、軽視してはいけない。

そういうことを考慮しない発言をすること、更に、その状況でも なぜか(どういう論理か不明だが)「安心」させて「数」を増やそうと企むことが、指揮者・発注者として失格というか、「無知無能は すっこんでろ!」だ。

そういう連中を弁護する意見に「トラブル0を求めるのは日本人の悪い癖」のようなものがあるが、それとは違う。トラブルを0にすること(無理だ)が目的とか重要なのでなく、起こったトラブルの原因を調べて、例えばシステムに予期せぬ問題がないか調べる・確かめることが重要なのだ。その結果、起こったトラブルが予期されたものであれば仕方ないし、安心できる。

言い換えれば、「問題は必ず起こるが、「だから問題ない」と言ったり、なかったことにするのは間違っている。」だ。

(8/22 4:59 加筆, 6:53 PS2を追加)

  •  1
  •  1
Keys: , , , , ,

ずっと やりたかったものの、大変そうだから延期し続けていたことが半分くらい片付いた。

Joplinは結構使い勝手が悪くて早く排除したかったので、業を煮やして「ちょっと」思い付いたことを試したら※意外にうまく行ったので(これが いつもの嵌まるパターン)、その方向で進めたら(これも悪手だ!)やっぱり大変だった。が、常々イライラしていたJoplinから どうにか脱却できそうなので、うれしい。

※結構前に、どういうふうに進めるか・するかを考えて居たが、ちゃんとやるのは大変な感じだったので進まなかった。そこで、一旦それを棚上げして思い付きを試してみた。テキトーに作るのは良くないが、停滞状態を変えるには こういうこともアリなのだろう。そのあとが大変だが。

以前書いたが、僕はJoplinをノートを書くために使っていない。MD(Markdown)で書くなんて面倒臭くてやってられないので、Zim(僕の改良版)で書いて※Joplinはスマフォ(サーバ)にノートを送ったり、画像をZimに貼り付けるためだけに使って居る。

※JoplinにもWYSIWYG編集モードがあるが、以前使ったら ひどいものだったので止めた。その他のWYSIWYGのMDエディタも僕には使いにくく、Zim(MDではない)だけが残った。

参考までに書くと、具体的な使い方は日々の買い物メモだ。それが90%以上だ。メモ用紙の削減に絶大な効果がある。詰まらないことだけど、例えば、日々変わる食品・日用品(例: レトルト食品)の有無・残量※は覚えられないし、紙に書いて更新・持参するのは非効率だ。

とは言え、紙のメモでなくてはならない場合もあるので、片方だけにすべきだとは思って居ない。適材適所だ。

※余談だが、ものの残量などを自分で調べてノートに打ち込むのは全くアナログだ。そこで、(半)自動で更新するようなシステムが便利そうだが、実現はなかなか難しい。冷蔵庫の中を調べる製品はあるようだが、そういうのでは全く不充分だ。

それから、良くあるアプリのパターンだが、それがスマフォだけでしか見たり更新できないのも不便だ。やっぱり、慣れたPCでも使えないと不便だ。もちろん、それらの間の転送も自動でないと面倒だ。

更に、気に入って使って居るのに、提供者の都合で勝手に改悪・終了されたりしたくないし、余計なお世話もされたくない!

それだけのことなのに、どうにも使いにくかった。Joplinや今までのシステムには以下の問題があった。

  • サーバとの同期が遅い、おかしい。
    • 特にスマフォでは、設定していてもバックグラウンドで同期することがない。
      • 電池の最適化をoffにすればいいかも知れないが(以前試して駄目だった気もする)、電池消費が激しくなりそうだ。
    • ノートを見る時に手動で同期するしかないが、2回連続して同期しないと最新版が表示されない。
    • 同期が すごく遅い。
      • 何をしているか分からないが、同期が始まるまでが特に長い(体感で1-2分くらい)。
      • 上述のように それが2回必要なので、とにかくスマフォでの同期は嫌だった。
  • スマフォアプリは使い物にならない。
    • 上の同期の問題以外に、遅い。大きなノートは まず開けない(実用的な時間では無理だし、大抵落ちる)。
    • 大きなノートのスクロールも困難。
      • 下のほうを見るには延々とスワイプし続ける必要がある。
        • ただし、ほとんどの他のアプリでも同様
  • メモリの大食い(特にPC)
    • Electronアプリのため、複数のタブ(ノート)を同時に開くのは全く実用的でない。
  • ディレクトリ構成が悪い。
    • すべてのノートの画像を一箇所(ディレクトリ)に格納しているため、僕の場合、そのファイル数が1万個を超え、負荷の増大や上述の同期速度の低下の原因になっていることが疑われる。
      • こんなに大きい画像ディレクトリはファイルマネージャでも容易には見られない。
    • この件以外にも、(技術的にはどうか分からないが、)システム構成を ちゃんと考えずに作った印象があり、将来性(ずっと使い続けられるか)は疑問だ。
      • 構成以外にも、独自のサーバを作ったりするのはいいけど、既存部分のサポートが いい加減な感じで、余り信用できない・付き合って居られない感じだ。
  • DBが不便かつ大きい。
    • ノートの文章はDB(sqlite)に格納されているが、Joplinなどを介さないと開けず不便なうえに、大きい(100MB以上)ので厄介だ。
      • インクリメンタルバックアップの容量が増大する。
    • その割には、サーバにはノートごとに格納しているようなのが謎。
    • DBの構成を見ると、似たようなフィールド(カラム)が沢山あって理解不能。
  • 勝手にバージョンアップして同期できなくなることがあった。
    • スマフォアプリのバージョンアップでサーバ内の構成が変わったらしく、PCにまで影響した。
      • PCのアプリには特にエラーが出ていなかったので、しばらく気付かなかった。
  • (Joplinだけでなく、JoplinとZimの関係による) 画像がZimのノートに手軽に貼り付けられない。
    • 主にJoplinとZimのディレクトリ構成の違いによるのだが、一旦 画像をJoplinのノートに貼り、そのノートをZimにインポートして、そこから本来のノートに貼り付ける必要があった。

今までの処理の流れ

今までは以下のようにして、PCで書いたノートをスマフォで見ていた。

  • PC
    1. Zim: 元のノートを書く。
    2. Zim+自作変換ソフト(zim2jop): ノートの更新を検出後、MDに変換してJoplinにエクスポートする。
    3. Joplin(PCアプリ): MD+画像をサーバに送る。
  • スマフォ
    • Joplin(Androidアプリ)
      1. MD+画像をサーバから取得する。
      2. 取得したMDを表示する。

なお、ZimやMDでなく、一般的なアプリ・ファイル形式を使えば良いと思われるだろうが、PCとスマフォでの操作性の良さの両立や規格のオープンさ(その会社・製品に依存しないために重要)などを重視して検討した結果 こうなった。

例えば、Evernoteなどは反オープンの極みだし、Office(Wordなど)は(特にスマフォで)煩雑だし余りオープンでない。HTMLはオープンだけど使い勝手が今一つだ。各社のメモアプリ(例: Google Keep)は汎用性・柔軟性がないし、フォーマットがオープンでないので その会社・製品に依存してしまう。

新しい処理の流れ(脱Joplin)

今回、以下のようにしてJoplinを排除することができた。

  • PC
    1. Zim: 元のノートを書く。
    2. Zim+自作変換ソフト(zim2md): ノートの更新を検出後、MDに変換してNextcloud(以下、NC)の同期ディレクトリに格納する。
    3. NCアプリ: MD+画像をサーバに送る。
    4. 自作同期プログラム(sync-zim-md-rem): MD+画像を直接スマフォに送る。 (7/31 6:09)
      • FolderSyncで定期的に同期させた時のスマフォの電池消費が気になったので追加した。 (詳細は後述)
  • スマフォ
    1. FolderSync: MD+画像をサーバから取得する。 (通常は上述の自作同期プログラムでPCから直接転送されているので、不要になった。: 7/31 6:09)
      • Zettel NotesのWebDAVでの同期に問題がある(後述)ので、それが直るまでは これを使うことにした。
      • 定期的な自動同期の他に、手動での同期も可能※
        • ※同期を開始するウィジェットをホーム画面に登録できるので、手軽に同期できる。
        • 使っていて分かったが、どういう仕組みか不明なものの、Zettel Notesでノート一覧を更新(下にスワイプ)すると同期が始まるようで、本当にそうなら上のウィジェットも不要で とても便利だ。 (7/21 17:21) ← 残念ながら、単にZettel Notesの更新中のマークが出ていただけだったようで、FolderSyncで同期は始まらない。 (7/22 18:27)
    2. Zettel Notes Epsilon Notes: 取得したMDを表示する。
      • 注: Zettel Notesの正当性が疑わしいため、使用を一旦止めてEpsilon Notesに切り替えた。 (下の「気になること」も参照のこと) (7/31 13:52)

実装などのメモ

  • このシステムではスマフォからPCへの逆同期も可能だが、スマフォで ちゃんと書く機会がほとんどないし、面倒で その気も起こらないので、今は実装していない。
    • スマフォでの簡単なメモは、(以前書いた)自作のメモシステムでPC(サーバ)に送れるので それで充分だし、書くたびに日時を手で入れる必要がないので便利だ。
  • MDへのエクスポート時のノートと画像のディレクトリ構成
    • ノート内の画像は、基本的にZimのエクスポートの仕様に従い、ノートと同じディレクトリにあるノートのファイル名+"_files"のディレクトリに格納するようにした。 (例: ノートのファイル名が"test"の時、画像ディレクトリは"test_files")
      • この時、同名(だけど中身が異なる)ファイルとの競合※を防ぐため、ファイルの中身のダイジェスト(またはハッシュ)をファイル名に追加するようにした。 (例: "image.png" → "image_726fa81814c56c6e.png")
        • ダイジェストにはCRC64を使った。
          • CRC64を計算するコマンドは ほとんどないが、調べたら7zでできることが分かった。 (→ 参照)
        • ※このディレクトリ構成ではZimに添付できている画像のファイル名が競合することはないが、仮に画像ディレクトリを共通にした時に効いてくる。
    • ただし、Joplinから取り込んだ画像は、従来との互換性維持と区別を容易にするため、ノートと同じディレクトリの"resources"というディレクトリに格納する。
      • Joplinの画像のファイル名は既にユニークなようなので(UUID?)、ダイジェストは追加せず、Joplinのものをそのまま使って居る。
      • これらは、将来 完全にZimに取り込んだ時に、上記のディレクトリに移る予定だ。
  • 更新されたノートの検出には、以前から興味があったinotifywaitを使った。
    • これにより、今まで無駄に定期的に(30秒にしていた)更新ファイルを検索していたのが不要になった。
    • また、ノートを書き込んでから変換を開始するまでの待ち時間※を、指定した値(今は3分にしている)に近付けることができた(ただ、そのメリットは余りない)。
      • ※書き込んですぐに変換開始すると、ノートの更新中に頻繁に変換することになって良くないので、こうした。
      • 待ち時間を実現するため、inotifywaitの出すファイル変更イベントの発生時刻とファイル名などをテーブルに保持するようにした。
        • 周期的なタイマーイベント(待ち時間の1/5にしている)やイベント発生時に、テーブルから待ち時間の経過したイベント(ファイル)を探す。
        • なお、イベントが頻繁に発生すると検索が無駄に多くなるので、前回の検索からの間隔がしきい値未満の場合は検索しないようにした。
      • この処理を独立のプログラム(スクリプト)にしたので、あとで何かに使えそうだ。
    • ただし、変換プログラムの起動時には前回の終了以降に更新されたノートが分からないため、従来の方法(指定時刻以降に更新されたものを検索)で検出している。
  • zim2mdはシェルスクリプトで、ずっと普通のsh(実際はdash)を使っていたが、配列が必要になってbashにしたら、原因不明のエラーが出て困った。
    • いろいろなオプションを試行錯誤しても直らなかったが、POSIXモード(--posix)にしたらエラーが出なくなった。特にPOSIXを意識して書いた訳ではなかった(「普通」に書いた)が、どこかにPOSIXだけでしか使えない記述があったようだ(そもそも、何がPOSIXか知らないw)。
      • ひどいのは、エラーの行番号がズレて出るため、本当にどこが悪いのか分からなかったことだ。
    • 気持ち悪いが どうにもならないので、とりあえずPOSIXモード専用とした。bash以外に配列が使える(軽い)shellがあれば良いのだが。
  • Zettel NotesやFolderSyncの電池消費が気になったが、頻繁に使わなければ問題なさそうだ。※
    • 電池の最適化のためか、スマフォが長時間スリープ中は同期間隔が伸びる(設定: 30分 → 3時間など)が、スケジュールなどと同様で、僕には好都合だ。 ← 使ってみたところ、どうやらFolderSync自体は きっちり間隔を守るようだ。長くなったのは、外から戻った時にWi-Fiがずっと繋がらなかったとか、一旦同期に失敗すると しばらく復活しないためではないか想像している。 (7/22 19:51)
    • ※その後、FolderSyncを動かしていると電池消費が高目(1%/h前後)になることがあるので、なるべく使わないような仕組みにした。別途または追って書きたい。 (7/27 17:28)
  • FolderSyncのWevDAVの接続情報(URLなど)の設定は難しい(謎)。
    • WevDAVサーバを標準ポートでなく、またサブディレクトリにインストールしている場合、「サーバーアドレス」にポート番号とサブディレクトリ(/remote.phpの前まで)を含めたURLを、「ポート番号」にポート番号をそれぞれ設定し、「ファイルパス」に/remote.php以降を設定する必要があった。
  • (7/31 6:09) 実際に使っていて、FolderSyncで定期的に同期させた時のスマフォの電池消費が大きくなることがあって気になったので、スマフォが家(LAN(Wi-Fi)内)にある時には、自作の同期プログラム(sync-zim-md-rem)でスマフォに直接送るようにし、FolderSyncでの定期的な同期は止めた。
    • sync-zim-md-remはシェルスクリプトで、上記のzim2mdが作ったMD+画像を定期的にrsyncでスマフォのMDのディレクトリ(FolderSyncの同期ディレクトリと同じ)に転送している。
    • 転送間隔が短いと電池消費が増える場合があったので、20分間隔にした。
    • 外出直前などにすぐに同期したい場合のために、ZimにMD変換と同期を行うカスタムツールを追加し、それを起動するボタンを付けた。
      • 仮に転送し忘れた場合でも、サーバからFolderSyncで同期することができる(可能性が高い: 外出の3分くらい前までPCを起動していれば良い)。
    • このプログラムは、元々、以前から使って居るスマフォ内の画像の自動取得プログラムに組み込もうとしていたが、自動取得プログラムの処理が複雑になってしまうので、(とりあえず)独立にした。
      • 自動取得プログラムと似た処理だが、近頃のLAN(Wi-Fi)構成の変化のためか随分簡単になったので、自動取得プログラムを改良できる余地がありそうだ。

昨日までに ここまで出来て、Zimにペースト・ドロップ・添付した画像をスマフォで表示できるようになった。そのため、通常はJoplinを使う必要が全くなくなり、すごく使いやすくなった。以下に表示例を示す。

まあ、何の変哲もない ただのノートアプリのキャプチャだし、ごく当たり前にできるはずのことだが、ここまで来るのは なかなか大変だった・・・

上のキャプチャを撮る時にも不具合が見付かり、芋づる式に いろいろ修正(仕様変更もあり・・・)して12時間以上掛かって、これを書くのの再開が今日になった。

残件

  • Joplinのノートを全部Zimに移す(引き上げる)。
    • 今は必要なものだけをZimに入れている。
      • Joplinのノートは全部で千個くらいあるようなので、自動化する必要がある。
    • Joplinの画像をZimに移すのが面倒。
      • ノート内の画像参照を変更する必要がある。
        • 今回も同様の処理(MD内の記述を書き換える)があったが、大変苦労した・・・
  • 細かい改良
    • 山ほどある・・・
  • 今までの不具合修正
    • これも多い・・・
      • 上の改良もそうだが、面倒なのと多少我慢すれば使えるので、延々と延期して来た。
    • 今回の変更で不要になったものも多そうだ。
  • デバッグ出力を減らす。
    • これが難しい。: 「出来た、大丈夫だ!」と思って減らすと問題が起こって、また出す羽目になることが多い。あと、通常時のチェック(たまに見ることがある)に必要な出力まで削ってしまって、役に立たなくなることもある。

気になること

  • Zettel NotesやFolderSyncの安全性(例: データ・アカウント情報の漏洩)と将来性
    • とは言え、Joplinが良かったかも不明
    • あと、近頃、ZNへの問い合わせ(Google groups)への回答が途絶えた。 → その後回答がなく、Google playのレビューで どうなってるのか聞いたら不可解な応答をしたため、怪しいアプリの可能性を疑い、使用を一旦止めてEpsilon Notesに切り替えた。 (7/31 13:52)
      • 今回のシステム構成は同期と表示を別のアプリにできるので、これが駄目なら別のもの(上記のように とても少ないが)に換えれば良い。
      • 別のもう1件には全く回答がないことも合わせて、今後も回答がないままなら、信頼できないから切ることもある。
        • 自分で作っているなら、問題の原因やヒントが分かりそうなものなのに、だんまりってのは怪しい。
        • ただ、外観や使い勝手を見る限り、これが何かのパクリとも思えないのが謎だ。
        • 課金する訳でもなくオープンソースでないのも、怪しさ(不信感)を増大させている。

 

おまけ: 試用したAndroidのMDエディタ・ビューアで良かったもの

Zettel Notesの次はEpsilonが良さそうな感じだ。 → (8/5 9:14) その後、Zettel Notesは不審なので止め、Epsilon NotesとObsidianを比較して全体的に少し良さそうな、Obsidianを使って居る。

  • × Zettel Notes (以下、ZN)
    • (8/5 9:14) MD表示の出来は一番良いものの、開発者が不審なので使用を中止した。推奨しない。
      • Google groupsでの問い合わせへの回答が突然止まった。回答のないものもある。
      • その件をGoogle Playのレビューに書いたら、Google groupsは知らん顔で別のところに書けという返事が来た。
    • 若干の問題はあるものの、いろいろ試した中では これが良さそうだったが、WebDAVでの同期に問題がある。
      • 問題の起こる詳細が分からないが、同期する画像ファイル数が多い場合、サーバから取得後、それらをサーバに送ってしまう。
    • 対応しているクラウドストレージとの使い勝手の比較
      • Dropbox: 変な("(",")"など、異常ではないが特殊な文字が使われている)ファイル名のファイルを無視する。無料の容量が小さ過ぎる。
      • (pCloud: 今一つメリットがない。パッとしない。): Zettel Notesは非対応。
      • Google docs: いつまで使えるの?? 信用できない。
      • sftp: 使い方が謎で使えなかった。
      • (DavX5のDAVマウント): Zettel Notesは非対応。
    • スマフォでの表示
      • 若干の問題はあるものの、いろいろ試した中では これが一番良さそうだった。
      • ただ、たまに変な表示になる。: キャプション(alt-text)の付いた画像を引用で表示すると、同じ画像が2つ表示される。下に問題の起こる例を示す。

> ![abc](resources/image.png)

        • MDへのエクスポート時にキャプションを出さないようにすれば解消するので、大きな問題ではない。
      • 大きいノートの表示は遅い。もたつく。
  • △ Epsilon Notes (以下、Epsilon)
    • ZNの画像の問題は起こらない。
    • メニューの構成が変
    • 設定のテーマが容易に変更できない。
    • ファイルマネージャ(CX File Explorer)のMDの「開く」に出るので便利そう。
    • Dropbox対応は有料
    • (8/5 9:14) MD(CommonMark)の解釈が厳密なため、いくつかの(Joplinに対する)互換性の問題がある(正しい動作だが、使いにくい)。
      • 「普通の」(または引用中の)改行が無視される。: 下の場合、行1と行2、あるいは行3と行4が繋がる。: CommonMarkでは間に空行(または空の引用)を入れるようだ。 → CSSを追加して緩和した。
行1
行2
> 行3
> 行4
      • 上・下付きに ^文字^, ~文字~ が使えない。: CommonMarkには ない。
      • 書式が空白を含んだり、英語・日本語が混ざると おかしい場合がある。Joplinや他のMDエディタでも起こったので、基本的な問題のようだ。: 下の場合、取り消し線が出ない。
~~aaa ~~bbb
  • △ Obsidian
    • ZNの画像の問題は起こらない。
    • ノートのフォルダが"Vault"なるものなのが面倒な感じ。
    • 表示は まあまあ。: (8/5 9:14) 全体的にはEpsilonより美しい。
      • 変な文字(異常ではないが、通常使われない文字)の表示が変。 (→ 例: Obsidian, ZN) ← フォントの変更で直る?
      • 大きいノート(test-diary-60)を開くのはEpsilonより遅いかも。
      • 設定したテーマが記憶されない?設定ファイルがサーバのもので上書きされたために起こったようだ。下を参照。 (8/5 9:14) ← 設定ファイルが上書きされなくても、勝手に設定が初期化されることがある。そうなる原因は分からない。 (8/11 14:31)
        • ただ、レビューでは そういう苦情を見ないので、僕の環境に原因があるのかも知れない。いずれにしても不便なので、再発したらEpsilonに移ろうと思っている。
    • Dropboxは非対応か有料
    • (8/5 9:14) MDの対応が異なる(CommonMark?)ため、いくつかの(Joplinに対する)互換性の問題がある。ただし、Epsilonよりは良い。
      • 上・下付きに ^文字^, ~文字~ が使えない。 (Epsilonと同様)
      • 書式が空白を含んだり、英語・日本語が混ざると おかしい場合がある。 (Epsilonと同様)
      • なお、Epsilonと違い、普通の(または引用中の)改行は無視されない。
        • 設定(Editor: Strict line breaksをoff)によるようだ。
    • (8/5 9:14) 設定ファイルがVaultに格納されるので、Vaultがサーバと同期されている場合、設定も同期されて予期せぬ問題となる。例: 上の「設定したテーマが記憶されない?」

他にもいろいろ試したが、まともに使えるものは本当になかった。なんで使えないものを出しているのだろうか?

 

おまけ: AndroidのMDエディタ(例: Obsidian, Epsilon Notes)で取り消し線の表示を見やすくする方法 (表示スタイルのカスタマイズ)

描画やフォントの関係だろうが、横線の多い単語(例: 牛丼)に取り消し(strikethrough)の書式を設定しても、見えにくい場合がある。僕の場合、PCはZimで、取り消しにすると文字の色もグレーになるから分かりやすいが、スマフォアプリは そうではないので見間違いやすい。

そこで試行錯誤したところ、アプリにCSSを追加設定すれば、色や線のフォーマット(太さや形状)が変えられることが分かった。方法はアプリごとに異なるが、以下にEpsilon NotesとObsidianの場合を示す。

Epsilon Notes

設定で追加のCSSファイルが指定できる感じだが、ファイル選択のダイアログは出ず、試行錯誤するのが面倒なので、標準のテーマ(Day)にスタイルを追加した。以下のように、del(CSSに詳しくないので、何というカテゴリか不明: タグ? セレクタ? クラス?)に設定すれば良い。

下のようにすると、取り消し線は茶色の太い波線になる。

del {
    text-decoration-style: wavy;
    text-decoration-thickness: 3px;
    text-decoration-color: maroon;

    /*text-decoration: line-through;*/
}

下では、Zimのように、取り消された文字が灰色になる。

del {
    text-decoration: line-through;
    /*text-decoration-style: wavy;*/
    text-decoration-thickness: 3px;
    color: gray;
    /* text-decoration-color: maroon; */
}

Obsidian

設定の"CSS snippets"に追加CSSファイルを指定する。そのファイルは(Vault)/.obsidian/snippets/*.css に置く。※ (設定の表記で誤解したが、"snippets.css"などではない。)

※スマフォ版では埒が明かず、Linux版で試行錯誤して ようやく分かった。

以下のように、.cm-strikethroughに設定するようだ。※ (念のためにdelにも追加したが、関係なさそうだ)。設定内容はEpsilon Notesと同様である。下のようにすると、Epsilon Notesの2番目と同様に、取り消し線が太線になり、取り消された文字は(Zimのように)灰色になる

※これもLinux版で開発者ツールで調べた。

.cm-strikethrough, del {
    text-decoration: line-through;
    /*text-decoration-style: wavy;*/
    text-decoration-thickness: 3px;
    color: gray;
    /* text-decoration-color: maroon; */
}

(7/21 17:21 少し追加、修正; 7/22 18:27, 19:51 修正; 8/5 9:14 「試用したAndroidのMDエディタ・ビューアで良かったもの」を修正・加筆; 8/9 9:35 おまけを追加; 8/11 14:31 Obsidianの設定が初期化されてしまう件について追記)

  •  1
  •  0
Keys: , , , , , , , , ,