はてなfotolife記法をリンクなしのimgタグに変換する

このブログでは、かなり昔から画像の下側に細いラインが挿入されてしまっていた。以前は、影の領域が広くて画像本体と離れていたのでそれほど気にならなかったのだが、影の領域がコンパクトになり画像本体と細いラインが近づくと、かなり気になる。さらにマウスカーソルを画像の上に置くと、灰色のマーカーラインまで現れる...。
f:id:zariganitosh:20121206084634p:image:w500]

いいかげん、どうにかしようと思って調べてみると、これはaタグのリンクに指定されたスタイルだった。管理 >> デザインのテーマのスタイルと、自分で設定したスタイルが影響しているようだ。

a:hover { color:orange; border:none; background:#ddd; }
  • 1つ言えることは、たとえ上記のスタイルが設定されていても影などの透明領域のない画像なら、下側の細いラインも、灰色のマーカラインも見えないのだ。
    • 画像の下に表示されているはずだが、すべてが不透明な画像だから見えないのだ。よって気にならない。
  • 問題となるのは、ウィンドウなどのスクリーンショットを撮影した影付きの画像だ。
  • それらの画像は、ほとんどはてなfotolifeにアップロードして利用している。
  • ツールバーの写真ボタンを押して、アップロードが完了するとfotolife記法で写真が埋め込まれる。
  • 今だったら、Retina環境に対応するため1000pxの画像をアップロードして、幅500で表示している。
[f:id:zariganitosh:20121206084634p:image:w500]
<a target="_blank" href="http://f.hatena.ne.jp/zariganitosh/20121206084634" class="hatena-fotolife"><img src="http://cdn-ak.f.st-hatena.com/images/fotolife/z/zariganitosh/20121206/20121206084634.png" alt="f:id:zariganitosh:20121206084634p:image:w500" title="f:id:zariganitosh:20121206084634p:image:w500" class="hatena-fotolife" width="500"></a>
  • 画像を表示するimgタグは、自動的にaタグで囲まれてしまうのだ。
  • aタグは、はてなfotolifeの画像ページへのリンクになっている。

スタイルシートの対策

  • 以上のとおり、状況はよく分かった。
  • 自分のブログ環境では、はてなfotolife記法のリンク付き画像に対して、余分な下線と灰色のマーカーラインが表示されないようにすれば良さそう。
  • そこで、以下のスタイルを追加した。
a:link.hatena-fotolife { color:none; border:none; }
a:hover.hatena-fotolife { color:none; border:none; background:none; }
  • hatena-fotolifeクラス属性のリンクについては、余分なものを表示しない設定。
  • プレビューしてみると、見事!下線と灰色のマーカーラインが消えている!満足。
  • ただし、flickrDropboxなどに影付きの画像を置いて単純にaタグで囲ってしまうと、その画像には下線と灰色のマーカーラインが表示されてしまう。
    • そんな時は、aタグのクラス属性にhatena-fotolifeを設定しておけば、余分なものは一切表示されなくなる。

リンクなしの画像に変換するサービス

  • そもそも自分のブログにおいては、ブログ内の画像から、はてなfotolifeへのリンクは不要だと思っている。
  • 容量の関係から、画像サイズは必要最小サイズかつ、必要最低品質に圧縮してアップロードしている。
  • そのような画像をわざわざはてなfotolifeに移動して閲覧しても、まったく嬉しくないはずである。
  • 他の画像もスクリーンショットばかりで、ブログ内の解説とともに見なければまったく意味がない。
  • そればかりか、リンク付き画像となってしまっていることで、不要な期待を抱かせているかもしれない。
  • 無駄にクリックさせてしまい、面白みのないリンク先へ移動してしまって、ガッカリしているかもしれない。

ならば、リンクなし画像にしてしまおう!

  • まずは、はてなfotolife記法がどのようなimgタグに変換されているか見極めてみる。
[f:id:zariganitosh:20121206084634p:image:w500]

<img src="http://cdn-ak.f.st-hatena.com/images/fotolife/z/zariganitosh/20121206/20121206084634.png" alt="f:id:zariganitosh:20121206084634p:image:w500" title="f:id:zariganitosh:20121206084634p:image:w500" class="hatena-fotolife" width="500">
  • 上段のはてなfotolife記法の情報から、下段のimgタグを生成すれば良いのである。
  • src、alt、title属性の内容を見ると、すべてはてなfotolife記法の情報に関連付けられていると想像できる。
  • class属性はおそらく常に"hatena-fotolife"に固定される。
  • :w500については後付けの情報なので、はてなfotolife記法に関係なく常にwidth=500を設定しておく。
  • 以上のような方針で、以下のAppleScriptを作ってみた。


--[:id:zariganitosh:20121204144833p:image:w500]
on run {input}
--set input to "[:id:zariganitosh:20121204144833p:image:w500]"

--Automatorサービスでtext item delimiterを使ってリスト変換するには、Unicode textにしておく必要があった
set unicode_input to input as Unicode text

set fotolife_text to unicode_input's items 2 thru -2 as text
set editList to split(unicode_input, {"[", "]", ":"})
--{"", "f", "id", "zariganitosh", "20121204144833p", "image", "w500", ""}

set r to {letter:editList's item 2 ¬
, id:editList's item 4 ¬
, dir:editList's item 5's items 1 thru 8 as text ¬
, name:editList's item 5's items 1 thru -2 as text ¬
, ext:editList's item 5's item -1 as text ¬
, kind:editList's item 6 ¬
, tail:editList's item -1}
if r's ext = "p" then set r's ext to ".png"
--{letter:"f", id:"zariganitosh", dir:"20121204", name:"20121204144833", ext:"png", kind:"image", option:"w500"}

set img_url to "http://img." & r's letter & ".hatena.ne.jp/" & r's kind & "s/fotolife/z/" & r's id & "/" & r's dir & "/" & r's name & r's ext
set img_opt to "width=500"
set img_tag to "<img src=\"" & img_url & "\" alt=\"" & fotolife_text & "\" title=\"" & fotolife_text & "\" class=\"hatena-fotolife\" " & img_opt & " />" & r's tail
return img_tag
end run
--<img src="http://img.f.hatena.ne.jp/images/fotolife/z/zariganitosh/20121204/20121204144833.png" alt=":id:zariganitosh:20121204144833p:image:w500" title=":id:zariganitosh:20121204144833p:image:w500" width=500 />

on split(src_text, delimiter)
set last_delimiter to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set res to src_text's text items
set AppleScript's text item delimiters to last_delimiter
res
end split

  • 上記AppleScriptAutomatorのサービスに組み込めば、はてなfotolife記法を選択してサービスを実行することでimgタグに変換されるのだ!
    • input as Unicode textは大事。
    • これに気付くまで相当悩んだ...。

f:id:zariganitosh:20121208083033p:image:w500]

ページ単位でリンクなし画像に変換する

  • 現状は、はてなfotolife記法を選択して、二本指タップ、サービスメニューからfotolife_to_imgtagを選択、imgタグに置き換えられる。
  • しかし、スクリーンショットをいっぱい使っていると、都度選択して変換する作業が面倒くさい。
  • さらに、過去の記事をリンクなし画像に変換しようとしたら、本文からはてなfotolife記法を探すのも結構たいへん。

ならば、ページ単位でimgタグに変換してみる!

  • 前回学んだ、はてなダイアリーの編集中の文字列を一括取得する技を利用。 set blog_text to textarea_edit_value()
  • 取得した本文の中から、はてなfotolife記法の部分を正規表現で抜き出す。 repeat with s in fotolife_tags(blog_text)
  • はてなfotolife記法を1つずつimgタグに変換して、置き換える。 replace(blog_text, s, fotolife_to_imgtag(s))
  • すべてimgタグに置き換えたら、必要なバックスラッシュをもう一度エスケープして、 replace(result, "\n", "\\n"); replace(result, "\"", "\\\"");
  • 最後にSafariで編集中のテキストエリアに書き込む。 write_textarea_edit(result)

注意:

      • 以下のAppleScriptは、自分が利用する範囲のはてな記法の書き方で問題なく変換するように作ってあります。
      • しかし、はてな記法すべてを網羅して対応できているかどうか怪しいです。
      • imgタグ変換後は必ずプレビューして、内容に問題がないことを十分確認してから保存ボタンを押してください。
      • 場合によっては、意図しない内容に書き変わってしまう可能性もあります。



set blog_text to textarea_edit_value()
repeat with s in fotolife_tags(blog_text) set blog_text to replace(blog_text, s, fotolife_to_imgtag(s)) end repeat

blog_text
replace(result, "\\", "\\\\") replace(result, "
", "\\n") replace(result, "\"", "\\\"") write_textarea_edit(result)



--レコードから文字列キー指定で値を取得する
on for_key(a_record, a_key) run script "on value_of(obj)
obj's |" & a_key & "|
end
me"
result's value_of(a_record) end for_key

--[:id:zariganitosh:20121204144833p:image:w500]
on fotolife_to_imgtag(input) set WH to {w:"width", h:"height"} set fotolife_text to input's items 2 thru -2 as text
set editList to split(input, {"[", "]", ":"}) --{"", "f", "id", "zariganitosh", "20121204144833p", "image", "w500", ""}
set r to {letter:editList's item 2 ¬ , id:editList's item 4 ¬ , dir:editList's item 5's items 1 thru 8 as text ¬ , name:editList's item 5's items 1 thru -2 as text ¬ , ext:editList's item 5's item -1 as text ¬ , kind:editList's item 6 ¬ , option:editList's item 7 ¬ , tail:editList's item -1} if r's ext = "p" then set r's ext to ".png"
--{letter:"f", id:"zariganitosh", dir:"20121204", name:"20121204144833", ext:"png", kind:"image", option:"w500"}
set img_url to "http://img." & r's letter & ".hatena.ne.jp/" & r's kind & "s/fotolife/z/" & r's id & "/" & r's dir & "/" & r's name & r's ext
if r's option = "" then
set img_opt to "width=500"
else
set optWH to r's option's item 1
set optPX to r's option's items 2 thru -1
set img_opt to for_key(WH, optWH) & "=" & optPX
end if
set img_tag to "<img src=\"" & img_url & "\" alt=\"" & fotolife_text & "\" title=\"" & fotolife_text & "\" " & img_opt & " />" & r's tail
return img_tag
end fotolife_to_imgtag
--<img src="http://img.f.hatena.ne.jp/images/fotolife/z/zariganitosh/20121204/20121204144833.png" alt="20121204144833" width=500 />

--はてなfotolife記法の部分を抜き出す
on fotolife_tags(str) --do shell script "echo " & quoted form of str & "|grep -e '\\[f:.*\\]'"
--do_ruby_script(quoted form of result & ".scan(/\\[f:.+?\\]/)")
--do shell script "echo " & quoted form of str & "|grep -e '\\[f:.*\\]'|ruby -r'jcode' -Ku -e 'STDIN.each_line{|line| puts line.scan(/\\[f:.+?\\]/)}'"
do shell script "echo " & quoted form of str & "|ruby -r'jcode' -Ku -e 'STDIN.each_line{|line| puts line.scan(/\\[f:.+?\\]/)}'"
split(result, return) end fotolife_tags

--ID属性'textarea-edit'のテキストエリアに値を書き込む
on write_textarea_edit(str) tell application "Safari"
do JavaScript "
var el = document.getElementById('textarea-edit');
el.innerText = \"" & str & "\";
" in document 1
end tell
end write_textarea_edit

--ID属性'textarea-edit'のテキストエリアの値を返す
on textarea_edit_value() tell application "Safari"
do JavaScript "
editText = document.getElementById('textarea-edit').value;
" in document 1
end tell
end textarea_edit_value

--テキストをリストに変換(区切り文字で分割する)
on split(src_text, delimiter) set last_delimiter to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set res to src_text's text items
set AppleScript's text item delimiters to last_delimiter
res
end split

--リストをテキストに変換(区切り文字で接続する)
on join(src_list, delimiter) set last_delimiter to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set res to src_list as text
set AppleScript's text item delimiters to last_delimiter
res
end join

--テキスト置き換え
on replace(sourceText, text1, text2) join(split(sourceText, text1), text2) end replace

--UTF-8な日本語環境でRubyコードを実行する
on do_ruby_script(code_list) set code_list to code_list as list
set code_list's last item to "puts(" & code_list's last item & ")"
set shell_code to "ruby -r'jcode' -Ku -e " & quoted form of join(code_list, ";") do shell script shell_code
end do_ruby_script

  • 改行を含むテキストの本文を、どうやってAppleScriptからRubyコードに渡すべきかかなり悩んでしまったが、
  • いったんシェルスクリプトでechoして、それをパイプで繋いでRuby側で標準入力として受け取ると、うまく処理してくれた。


do shell script "echo " & quoted form of str & "|ruby -r'jcode' -Ku -e 'STDIN.each_line{|line| puts line.scan(/\\[f:.+?\\]/)}'"

  • 以上のスクリプトは、AppleScriptとして保存して、ショートカットを割り当てて呼び出すことにした。
  • リンクなしの画像にしたい日記を編集モードにして、ショートカットを実行すれば、リンクなしのimgタグに一括変換されるのだ!

開発&利用環境