Monthly Archives: 3月 2012

2012-03-21

出家とその弟子

確かtwitterで言及されていて興味を持ったんだと思ったけど、出家とその弟子を読んだ。たまにはこういうのを読むのも良いね。

どんなに考えてみても人間ではどうにもできないと思えるから祈るとか願うとかするしか無いでしょ、みたいな感じかなぁ。私は何か超越的な存在(例えば仏様みたいなの)を具体的に信じているわけでは無いので、祈って神仏におすがりする、みたいなのはゾッとする(まあ、すがれとは言っていないと思うけど)。しかし、繰り返し祈り、願うことによって深層意識というか、脳に実現しやすい性質をすり込んでいくというのならば、まだ分からなくも無い。どのみち証拠も無い分からない話ではある。

2012-03-18

書けない

う゛ー、構文解析が難しい。書こうと思えば多分書ける。だが、いくつか問題が生じる。

というか、構文自体に多少の問題がある。このままの構文だとネストしたときに書けなくなる構文がまれではあるが出来てしまう。それを防ぐには普段よく使う構文を多少見た目が悪いものにする必要があるように思う。でもそれは嫌だ。まれにしか使わない書き方のためによく使う書き方を犠牲にしたくない。それに、そのまれにしか使わない書き方は別に書けなくても回避方法はいくらでもある。すべてが丸く収まる構文が思いつけば良いのだが、どうも思いつきそうも無い。

実装自体にも多少問題はある。文脈によってキーワードにするものを細かく変えなければならない。それも、ネストする度に特殊な解析モードを入れたり切ったりしなければならない。あんまりそういうことをするとエラー回復が難しくなるからやりたくないんだけどなぁ。

2012-03-11 ,

org-modeで画像へのURLリンクをインライン表示

org-modeには画像のリンクをインラインで表示する機能がある。

[[file:hoge.png]]

のようなリンクがあった場合に、org-toggle-inline-images ( C-C C-x C-v ) でインライン表示するかどうかをトグルで切り替えられる。

しかしこの機能はURLには対応していない。

[[http://www.google.co.jp/images/srpr/logo3w.png]]

のようなリンクがインラインで表示されないのである。

なので、それが出来るようにしてみた。

結果のソースコードはorg-http-inline-image.el

http経由で画像を取得

まずはウェブ上からhttp経由で画像を取得する方法について調べた。

(insert-image
  (create-image
    (with-current-buffer
      (url-retrieve-synchronously
        "http://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/260px-The_Earth_seen_from_Apollo_17.jpg")
      (buffer-substring (re-search-forward "\n\n") (point-max))) nil t))

これで任意のURLから画像を取得できる。

url-retrieve-synchronouslyで画像データを含んだバッファを作成し、
HTTPヘッダを除いた部分を取り出してcreate-imageしているだけ。

試しにinsert-imageするとバッファに画像が表示されるはず。

本当は非同期にしたり画像をキャッシュしたりエラー処理をしないとダメなんだろうけど、まずは最低限のコードが知りたかったので。

あと、kill-bufferした方がメモリ的には良いのかもしれない。

org-display-inline-imagesの改変

画像のインライン表示はorg.el内のorg-display-inline-imagesで行っている。

この関数は7.8.03の時点では次のようになっている。

(defun org-display-inline-images (&optional include-linked refresh beg end)
  "Display inline images.
Normally only links without a description part are inlined, because this
is how it will work for export.  When INCLUDE-LINKED is set, also links
with a description part will be inlined.  This can be nice for a quick
look at those images, but it does not reflect what exported files will look
like.
When REFRESH is set, refresh existing images between BEG and END.
This will create new image displays only if necessary.
BEG and END default to the buffer boundaries."
  (interactive "P")
  (unless refresh
    (org-remove-inline-images)
    (if (fboundp 'clear-image-cache) (clear-image-cache)))
  (save-excursion
    (save-restriction
      (widen)
      (setq beg (or beg (point-min)) end (or end (point-max)))
      (goto-char (point-min))
      (let ((re (concat "\[\[\(\(file:\)\|\([./~]\)\)\([^]n]+?"
                        (substring (org-image-file-name-regexp) 0 -2)
                        "\)\]" (if include-linked "" "\]")))
            old file ov img)
        (while (re-search-forward re end t)
          (setq old (get-char-property-and-overlay (match-beginning 1)
                                                   'org-image-overlay))
          (setq file (expand-file-name
                      (concat (or (match-string 3) "") (match-string 4))))
          (when (file-exists-p file)
            (if (and (car-safe old) refresh)
                (image-refresh (overlay-get (cdr old) 'display))
              (setq img (save-match-data (create-image file)))
              (when img
                (setq ov (make-overlay (match-beginning 0) (match-end 0)))
                (overlay-put ov 'display img)
                (overlay-put ov 'face 'default)
                (overlay-put ov 'org-image-overlay t)
                (overlay-put ov 'modification-hooks
                             (list 'org-display-inline-modification-hook))
                (push ov org-inline-image-overlays)))))))))

この関数は、

  1. refreshでないときは既存のインライン画像をすべて取り除く。
  2. インライン表示対象となるリンク文字列を検索する。
  3. 見つかったリンクに対して、ファイル名が有効なら、そのファイルの画像を作成して、リンクの範囲にオーバーレイとして設定する。ただし、refreshでかつ特定の条件を満たせば、新しい画像は作らない。

といった動作をしている。

どうしたものか。

まず、httpリンクを見つけ出さなければならない。

正規表現部分の三つ目の開き括弧部分にhttpを入れることにした。

(let ((re (concat "\[\[\(\(file:\)\|\([./~]\|http://\)\)\([^]n]+?"
                  (substring (org-image-file-name-regexp) 0 -2)
                  "\)\]" (if include-linked "" "\]")))
      old file path ov img)
  (while (re-search-forward re end t)
    (setq old (get-char-property-and-overlay (match-beginning 1)
                                             'org-image-overlay))
    (setq file (concat (or (match-string 3) "") (match-string 4)))
    (setq path (expand-file-name file))

httpの部分はファイル名に含めたかったので、二つ目では無く三つ目にした。
それに伴い変数fileはexpand-file-nameする前のファイル名にして、変数
pathはexpand後にしてある。

次に実際に画像を用意するところだが、このままだと少し見通しが悪い。
新しいオーバーレイを作る部分を別の関数に分離してみた。

       (when (file-exists-p file)
         (if (and (car-safe old) refresh)
             (image-refresh (overlay-get (cdr old) 'display))
           (setq img (save-match-data (create-image file)))
           (my-org-add-inline-image-overlay img))))))))

(defun my-org-add-inline-image-overlay (img)
  (when img
    (let ((ov (make-overlay (match-beginning 0) (match-end 0))))
      (overlay-put ov 'display img)
      (overlay-put ov 'face 'default)
      (overlay-put ov 'org-image-overlay t)
      (overlay-put ov 'modification-hooks
                   (list 'org-display-inline-modification-hook))
      (push ov org-inline-image-overlays))))

少し見通しが良くなった。下半分はファイルでもURLでも共通の処理であり、問題は上半分だけとなった。

さて、ファイルへのリンクかURLへのリンクかによって処理を変えたいのだが、どうしたら良いだろうか。

問題の部分。

(when (file-exists-p file)
  (if (and (car-safe old) refresh)
      (image-refresh (overlay-get (cdr old) 'display))
    (setq img (save-match-data (create-image file)))
    (my-org-add-inline-image-overlay img))))))))
  • 1行目はファイルの時の処理。
  • 2行目~3行目はURLのときでも同じ処理。
  • 4行目はファイルの時の処理。
  • 5行目はURLの時でも同じ処理。

このようにファイルの時の処理とURLと共通の処理が交互に現れていて分離するのが先ほどと比べて難しい。

ここはlambdaを使って共通の処理だけをくくりだしてみた。

    (cond
     ((string= (match-string 3) "http://")
      (my-org-update-inline-image
       refresh (lambda () (save-match-data (my-org-create-image-from-url file)))))
     ((file-exists-p path)
      (my-org-update-inline-image
       refresh (lambda () (save-match-data (create-image path))))))))))

(defun my-org-update-inline-image (refresh loader)
  (let ((old (get-char-property-and-overlay (match-beginning 1)
                                            'org-image-overlay)))
    (if (and (car-safe old) refresh)
        (image-refresh (overlay-get (cdr old) 'display))
      (my-org-add-inline-image-overlay (funcall loader)))))

あとはURLから画像を読み込む関数が有れば良い。

(defun my-org-create-image-from-url (url)
  (let* ((buf (url-retrieve-synchronously url))
         (res (if buf (with-current-buffer buf (buffer-string))))
         (sep (if res (string-match "nn" res)))
         (data (if sep (substring res (+ 2 sep))))
         (img (if data (create-image data nil t))))
    (if buf (kill-buffer buf))
    img))

nilチェックやkill-bufferで不要になったバッファを削除したりしている。

2012-03-10

ネットプリント

初めてネットプリントを使ってみた。Web上で表示された申込書を印刷するため。現在自宅にはプリンターが無いので。

PDF(XPSでも良いんだろうけど、何となくPDF)へ「印刷」して、出来たファイルをネットプリントのサイトからサーバーへ送信して登録完了。セブンイレブンのコピー機みたいなのに予約番号と20円を入れて印刷。

うん、これは良いものだ。前々から場所を取らないモバイルプリンターでも買おうかなと思ったいたのだけど、これでますます不要になった。

知り合いによると、お店のクーポン券をネットプリントに登録しておいて、必要になったらセブンイレブンで印刷したりといった使い方も出来るらしい。

他にも予約番号をtwitterで配布して手書き新聞を配布したり、ミニコミ誌を配布するのに使っている人もいるらしい。

AndroidやiPhoneのアプリもあるので、出先で写真を撮ってすぐに印刷ということも出来そうだ。