2018/11/23(金)PinterestでPINした画像をGoogleドライブに保存できるようにする

■やりたいこと
PinterestでPINした画像をローカルで閲覧したい。おおむね、お絵描きの参考用途。
・ブラウザ窓だと参考画像として扱いづらい
・貧弱な通信環境でも閲覧できる
・いちいちブラウザ開くのが面倒

やっぱりローカルでアクセスできた方が便利だよね。

■調査と課題
直接Pinterestからデータを引っ張ってくることもできるが、定期実行なり待受の仕組みを立てる必要がある。可用性を高く、一方でできるだけ手間や予算がかからない方法を検討したい。自前サーバがあるのでこれを使ってももちろん良いのだが、可用性であればやはりクラウドに軍配が上がる。(半ば興味本位で)極力クラウドサービスだけで構成することを目指す。

ストレージサービスは一般にローカル同期の仕組みを持っているため、Pinterestからストレージサービスに連携できれば要求が満たせそう。

Pinterestとローカルサービスを繋ぐ方法として、IFTTTなどの連携機能構築サービスが有る。まずはこれを調査した。おおむね、パーソナル用途で機能と使いやすさを両立しているのは2018/10現在下記3つくらい。

・IFTTT(Maker)
・Microsoft Flow
・Integromat

これら全てに、Pinterestインプット・Googleドライブアウトプットアダプタがあった。
なのでこれらを繋げばいいだけに思える。

しかし、いざ使ってみると画像ではなくhtmlファイルが連携される。
どれもPinterestが公式で提供したアダプタらしく、画像そのものを外部サービスに渡さない意図的な作りと思われる。

ちなみに、各サービスの比較としては、
▼機能性
Microsoft Flow > Integromat > IFTTT

▼簡便性
IFTTT > Integromat > Microsoft Flow

高機能な方が一見良さそうだが、この手のクリックアンドポイントロジック構築は高機能にするほど最終的にフローチャート作成サービスになってしまい見通しやメンテナンス性が怪しくなるという特性がある。
複雑なものを作ろうとするほど、どこかの境界でコードを自分で書いたほうが俯瞰性が良くなる。

IFTTTはINPUT(THIS)とOUTPUT(THAT)の接続だけしか選べないが、これくらいがちょうど良いように思う。見通しが悪くならない範囲で足すなら、出力を多数化(3つまでとか)、フィルタを一段、データ加工を簡単なもので1段くらいだろうか(その場合IFTTT以外のサービスないしMakerを選ぶことになる)。

いずれのサービスもコール回数に制限がある。
今回用途では1日10枚以内が目処。
上記に挙げた3つのフリープランでいずれも問題なさそうだった。

将来増えるか減るかなどの見通しは不明。

さて、結局以下のように構成した。

■実装
IFTTT⇒Google Apps Script(GAS)⇒Googleドライブ⇒ローカル(Googleドライブの連携機能)

・IFTTTからpinterestのurlをGASに渡す
・GAS内で、FetchしてPinterestのhtmlを取得
・簡単な正規表現マッチで画像URLおよび属性情報を取得
・画像をFetchしてGoogleドライブへ保存
・ファイル名はID+PINの詳細があればそれをファイル名とする
・第一階層のボード名をフォルダとしてそこに保存する

1) GASで下記スクリプトを作成。作成時に各種認証を要求されるので設定してやる。
function doPost(e) {
  // パラメータの取得
  var jsonString = e.postData.getDataAsString();
  var data = JSON.parse(jsonString);
  var pinUrl = data.pinUrl;
  var boardName = data.boardName;
  
  // フォルダ無ければ作成  
  var rootFolder = DriveApp.getRootFolder();
  var pinterestFolder = null;
  var targetFolder = null;
  var folderIterator = rootFolder.getFoldersByName('pinterest');

  if (folderIterator.hasNext()) {
    pinterestFolder = folderIterator.next();
  } else {
    pinterestFolder = rootDir.createFolder('pinterest');
  }

  targetFolder = pinterestFolder;

  // ボード名が取れていればサブフォルダとしてボードフォルダを作成
  if (boardName) {
    folderIterator = pinterestFolder.getFoldersByName(boardName);
    
    if (folderIterator.hasNext()) {
      targetFolder = folderIterator.next();
    } else {
      targetFolder = pinterestFolder.createFolder(boardName);
    }
  }
  
  // html解析処理
  var pinResponseText = UrlFetchApp.fetch(pinUrl).getContentText();
  var imageUrl = pinResponseText.match(/property="og:image".*content="([^"]*)"/)[1];
  // 128文字まで
  var description = pinResponseText.match(/img alt="([^"]*)"/)[1].substring(0, 128);
  
  var imageFilename = pinUrl.match(/[^\/]*$/)[0];
  
  // 画像取得処理
  var imageResponse = UrlFetchApp.fetch(imageUrl);

  // 拡張子は画像本体のContent-Typeから作成  
  var imageFilenameExt = imageResponse.getHeaders()["Content-Type"].match(/image\/([a-zA-Z]*)/)[1];
  if (imageFilenameExt == 'jpeg') {
    imageFilenameExt = 'jpg';
  }
  
  var imageBlob = imageResponse.getBlob().setName(imageFilename + ' - ' + description + '.' + imageFilenameExt);
  
  targetFolder.createFile(imageBlob);
  
}
IFTTTから呼び出せるようにWebアプリケーションとして公開してやる。


2) IFTTTで、Pinterestのオフィシャルアダプタを使いWebHookでGASに連携する。設定は以下。

▼THIS(INPUT)
Pinterest公式の"New Pin on your board"
Pick a board: "Any Board"

▼THAT(OUTPUT)
IFTTT公式の"Make a web request"
URL: https://script.google.com/macros/s/****/exec
Method: POST
Content Type (optional): application/json
Body (optional):
{"pinUrl":"{{PinURL}}", "boardName": "{{Board}}"}
以上で完成。かなりお手軽。

■まとめと使い勝手について
クラウド、フリープラン、更には認証情報をOAuthの世界で完結させたPinterest画像のローカル保存サービスが構築できた。
目標は達成でき、そこそこ便利に使っている。
ただ、PinterestからIFTTTへの発火に少しラグが有り、Googleドライブへの連携にもラグがあるためあまり即時連携という感じにはならない。

特性を理解して使用しつつ、どうしても即時で必要な場合はChromeの拡張などを利用してダウンロードすることにする。

■IFTTTについて
便利。機能を絞っているところが良い。
もちろん絞ってる分できないことがでてくる。
直感的に苦手なことはわかるので、あとは自分が使う上でどういったところでIFTTTで完結できないのか何を組み合わせればよいのかを今後確認していく。

■Google App Script(GAS)について
ロジックを作る必要があり、アウトプットがGoogle関係であればこれ一択。
Javascriptで大体何でもできるし、ドキュメントの必要十分さ、特に開発環境の素晴らしさはワンダフル。

現状無料で使えてるが、将来的に有料化or閉鎖しないかはちょっと心配。あとは制限。
作るときはフェッチの制限を忘れていたがやっぱりあるよね。
Google_Apps_Scriptの無料制限メモ
今回の内容だとURL Fetch 100MBが制限になりそう。
この仕組に限定すれば数百枚くらいは耐えるだろう。

AWSで相当するのは、Amazon API Gateway + Lambdaだろうか。
こいつらは本番運用には良いが、作って動かすまでのハードルが低くない。
こういったミニサービスや、使い捨てのテストAPIなどを作りたい場合GASのほうが向くように思う。


■今後の課題
サービスの選択・組み合わせを継続的に知識アプデするのと、GASがかなりawesomeだったのでできることを覚えたい。


■結論
最近のグルーサービスすげえね

2015/07/09(木)logbackでサイズローテートしない

logbackでログがファイルサイズでローテートしない問題。

Java1.7 + logback-1.1.3

条件は実行時間が短いバッチのようなプログラム。

もともと↓の記述にしていたのだが、ローテートしてくれなかった。
[logback.xml]
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>./logs/hoge.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>./logs/hoge.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>
    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger\(%F[%L]\) - %msg %n</pattern>
      <charset>Shift_JIS</charset>
    </encoder>
  </appender>
調べてみると、logbackのSizeBasedTriggeringPolicyはI/O負荷対策のためファイルサイズを毎度チェックしにいかない。デフォルトでは16回に1回であり、16回ログ出力して初めてサイズチェックに行く。ログ出力の頻度が多いと間隔を開け、頻度が少ないと間隔を狭める。

今回のプログラムは16回ログを出すフローがほとんどない。実行時間も短いため、間隔調整の恩恵も受ける暇がない。親切ではあるのだが、プロセス内の初回はチェックするなど対策が必要に思う。

このプログラムごく短時間で起動->終了し、ログの出力回数・起動頻度とも高くない。毎回チェックとしたい。

[logback.xml]
    <triggeringPolicy class="foo.bar.CustomSizeBasedTriggeringPolicy">
[カスタムクラス]
package foo.bar;

import java.io.File;

import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.util.FileSize;

public class CustomSizeBasedTriggeringPolicy<E> extends SizeBasedTriggeringPolicy<E> {

	String maxFileSizeAsString = Long.toString(DEFAULT_MAX_FILE_SIZE);
	FileSize maxFileSize;

	public CustomSizeBasedTriggeringPolicy() {
	}

	public CustomSizeBasedTriggeringPolicy(final String maxFileSize) {
		setMaxFileSize(maxFileSize);
	}

	@Override
	public boolean isTriggeringEvent(final File activeFile, final E event) {
		//オリジナルのisTriggeringEventでは発火しないことがあるため、ログ書き出しごとにチェックする
		return (activeFile.length() >= maxFileSize.getSize());
	}

	@Override
	public String getMaxFileSize() {
		return maxFileSizeAsString;
	}

	@Override
	public void setMaxFileSize(String maxFileSize) {
		this.maxFileSizeAsString = maxFileSize;
		this.maxFileSize = FileSize.valueOf(maxFileSize);
	}
}
isTriggeringEventだけいじったクラスを作成してやって、logback.xmlでそちらを見るようにしてやる。

とりあえずこれで動くことは動く。

2015/07/09(木)LogbackでプロセスIDを出力

logbackでプロセスIDを出す方法。

Java1.7 + logback-1.1.3

あまりいい方法が見つからなかったが、とりあえず出りゃいいやまではできた。

起動コマンドなりスクリプトなりがいじれるのなら、SystemProperty経由で設定・取得する方法が使える。

[起動コマンド]
exec java -Dpid=$$ -jar /foo/bar.jar
[logback.xml]
<pattern>%d{yyyy/MM/dd HH:mm:ss} [${pid}] %level %msg%n</pattern>
-Dpid=$$で、プロパティ:pidにプロセスIDをセット、patternに${pid}と記述してやるとlobackの機能で出力できる。
もちろんUnix環境限定。

なお、シェル側のプロセスIDがほしい場合は、execを外し直接javaコマンドをたたく。
java -Dpid=$$ -jar /foo/bar.jar
Webアプリケーションで動いている場合は、何がしかプロセスIDに相当するものがSystemPropertyにいると思うので${}でそれを拾えばいい(はず)。

本当なら、ManagementFactory.getRuntimeMXBean()で取得するのが正解のようだが、その場合PatternLayoutをカスタムしてコンバータをいじって… とやらなければいけない気がする。規模によってはさすがに大仰か。

[参考]
Igor Minar's Blog: How a Java Application Can Discover its Process ID (PID)

2014/08/12(火)TOMCAT + logbackで、logback.xmlを外出し

アプリケーションサーバ:TOMCAT、ログライブラリ:logbackの組み合わせで、
logback.xmlをwarの外に追い出そうとしたらプチハマリしたメモ。

環境は、
TOMCAT 7.0.54.0
logback 1.1.2

一応できた。ただし、すっきりとは書けない。

Context定義にVirtualWebappLoaderを追加する。
たとえば、WEB-INF以下にlogback.xmlを置いた場合以下のようになる。
<Context>
  <Loader
    className="org.apache.catalina.loader.VirtualWebappLoader"
    virtualClasspath="C:/foo/bar/WEB-INF"
  />
<Context/>
ここで注意。
必要なのがlogback.xmlだけの場合、ファイル名まで書いてやりたいので次のようにしがち。
    virtualClasspath="C:\foo\bar\WEB-INF\logback.xml"
しかしこの場合、VirtualWebappLoader側はlogback.xmlを認識するが、logbackがlogback.xmlを読みにいかない模様。
あくまでディレクトリパスを書く必要がある。

絶対パスなのがいまいちな場合、$tomcat.base or $tomcat.homeが使えるのでそれを使ってなんとか相対パスで書く。
(tomcat.home->catalina.homeかもしれないのでRTFM)。
    virtualClasspath="${tomcat.home}/webapps/foo/bar/WEB-INF"
このどっちもいまいちだと難しい。TOMCATではほかの手が見つからなかった。
アプリケーションサーバを切り替えたほうがいいかもしれない。

アプリケーションルート的な所から相対パスでアクセスしたいという要望はあると思う。

あとはメモ。
virtualClasspathの書き方としては、Windows環境下ではディレクトリ区切り子は"/"でも"\"でもよい。
ディレクトリパス指定時は末尾の区切りはいらない。

Context周りの仕様で怪しいところがあるなら本家ドキュメントで確認。Apache Tomcat 7 Configuration Reference (7.0.55) - The Context Container

Eclipseからプラグイン経由で使う場合、さらにいろいろ留意。

Eclipse+Tomcat Pluginでコンテキスト定義に追加する場合、プロジェクトのプロパティ->Tomcat->全般->その他の情報にLoaderセクションをべたっと貼り付けて、プロジェクト->右クリック->"コンテキスト定義を更新"でよい。

コンテキスト定義をMETA-INF/context.xmlなどで作っていても、現在のEclipseのTomcatプラグインは拾う機能がなさそう。コンテキスト定義更新で%CATALINA_BASE%/conf以下に反映されていないことに注意。META-INF側はconfより優先順位が低く参照されない。


こっから下はおまけ。
動作確認時に%CATALINA_HOME%/conf/logging.propertiesに、ログ出力を追加してTOMCATにログをはかせるようにした。
org.apache.catalina.loader.VirtualWebappLoader.level = ALL
org.apache.catalina.loader.VirtualWebappLoader.directory = ${catalina.base}/logs
なお、Eclipseから起動したTOMCATはcatalina.*.logとかははかないので注意。
ここら辺は"eclipse, tomcat, ログ"とかで検索してほしい。

2014/02/26(水)Ruby 1.9以降のirbでBackspaceで表示が崩れる

Ruby1.9以降(mswin32版)のirbで、Backspaceでの削除時に表示が崩れる問題。

環境はWindows7(64bit)。

消そうとした文字の1文字手前が消えたり、カーソルがプロンプトにめり込んだりとなかなかに怪しい。

画面にフラッシュされるのも数秒程度の遅延がある場合がある。

内部データは正常、あくまで表示が崩れているだけのようだが煩わしいので直したい。

下参照。

ruby - Backspace and arrow keys aren't working in IRB(Git Bash console) on windows machine - Stack Overflow

とりあえずirbで使用しているreadlineライブラリ周りに問題があるのは間違いない。

--noreadlineオプションを使えば問題は解消するが、Up-Keyでのhistory等は効かなくなる。

mingw32版ではこの問題はない。[2014/03/31 下に追記した]
なんだかめんどくさいなあ。

[2014/03/31追記 ここから]
と上では書いたが、mingw32版でも遅延があった。

irbについては、--noreadlineであっても何か1文字入力すればUp-Keyでhistoryが動くようだ。これでいいことにする。

Windowsの Users\<ユーザ名>以下に設定ファイルを置いてやって、irbはreadline不使用をデフォルトにする。

Users\<ユーザ名>\.irbrc
IRB.conf[:USE_READLINE] = false
ついでに、pryも同様の問題を抱えてるので直したい。
が、pryには--noreadlineオプションがない模様。
しゃーないのでコンフィグを怪しげにいじる。

[参考]
Changing Pry.config.input makes the prompt disappear · Issue #821 · pry/pry · GitHub

pry.config.inputをSTDINに差し替えるとreadlineが外せるらしい。
ただし、これをするとプロンプトを自前で表示しないといけない。

以下を参考に、
Rubyistよ、irbを捨ててPryを使おう - TIM Labs

Users\<ユーザ名>\.pryrc
Pry.config.input = STDIN
Pry.config.output = STDOUT

Pry.config.prompt = [
  proc {|target_self, nest_level, pry|
    nested = (nest_level.zero?) ? '' : ":#{nest_level}" 
    prompt = "[#{pry.input_array.size}] #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}(#{Pry.view_clip(target_self)})#{nested}> "
    print prompt
    prompt
  },
  proc {|target_self, nest_level, pry|
    nested = (nest_level.zero?) ?  '' : ":#{nest_level}"
    prompt = "[#{pry.input_array.size}] #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}(#{Pry.view_clip(target_self)})#{nested}* "
    print prompt
    prompt
  }
]
promptの表示を追加。
プロンプト内容はお好みで。
Pry.config.output = STDOUT行が必要かはちゃんと判断していない。

このやり方では入力後に改行が重複出力される問題がある。
また、起動直後にプロンプトがwarningなどと重なるので1回Enterしないといけない。
個人的には許容範囲内だが気になる人は気になるかも。

pry初心者なので、pryの全機能が不足なく動くかは確認していない。
なお、ターミナル上での日本語文字化けが改善するケースがある(追求していない)。

さて、readline周りの挙動は悩ましい。自分でコンパイルすれば直りそうなのだが、やりたくないなあ… やるんだったら配布までやらなきゃだと思うので。
[2014/03/31追記 ここまで]

さて、--noreadlineオプションは記憶しておくとして、Windowsに入れているRubyの措置について考える。

・mswin32版 -> mingw32版にする?
する。PATH環境変数と、スクリプト起動用のexeパスを書き換えた。

とりあえず、mingw32を避けてるのも変なので使ってみるというのが一つ。

mingw32版はcygwin版のようにcygwin周りのファイルが必要ということはないので、mswin32版とほぼ同じように使っていける(はず)。2.1.0が来てないあたり、若干保守的な様子。高速化はmingw32版の方が効いているとのこと。

mswin32版はgemでコンパイルをかけるような場合ではどうもトラブりやすい。pryにしろ、atomicにしろ自分の腕ではgem installに失敗したし、これを打開するためのコストをかけるほどの余裕がない。exerbとかが標準梱包なのは有り難く、gemで追加しない分にはこちらの方が便利か。オフィスでオフラインで使用する場合などではmswin32版の方がうれしいかも。DXRubyが入ってるのも楽しい。

・CP932なrubyスクリプトのエンコードをUTF-8に変える?
変えない。今回は断念して、マジックコメントでWindows-31J指定が入ってないものには追加。

動いてるスクリプトが、コマンドラインから日本語を含むファイル名を受け取って動くようなものが多いため、テストに時間がかかるというのが一つ。

Windowsのファイル名を扱う以上どうしてもSJISで処理したほうが楽だというのも間違いはない。今後UTF-8混じりのファイル名などでバグが起きない限り、既存のスクリプトはこのままにしておいて新規作成分はUTF-8で作ることにする。

2014/01/18(土)Rubyでtwitterライブラリを動かすまでのあれこれ

環境はWindows7(64bit)。

各所にやり方はまとまっているのだが、ここしばらくのTwitterの仕様変更やRuby特有のwinケアの甘さでちょいハマリしたのでメモ。

なお、gem installの項でmswin32版(ActiveScriptRuby 1.8~2.1全て)は環境構築できなかったので、minGW版 2.0.0の話になる。

gem install twitter周り

gem install twitterが通らない。依存で入ってくる"atomic-1.1.14"パッケージが鬼門の模様。
atomic_reference.c(75) : fatal error C1189: #error :  No CAS operation available for this platform
このエラーで止まる。

mswin32版では結局打開できず。

minGW版で打開できた。
どうやらコンパイラ=gccかつgcc4.8.1以降でないとソース変更なしではコンパイルできないらしい。以下参照。
failed compile with atomic-1.1.14.gem · Issue #32 · headius/ruby-atomic · GitHub

バイナリを集める。

RubyInstaller for Windows
minGW版Ruby最新の2.0.0-p353+DevKit-mingw64-32-4.7.2-20130224-1151を取ってくる。

MinGW | Minimalist GNU for Windows
gccはDevkitの4.7.2では×。MinGWを別に入れてgcc 4.8.1を取ってくる。

以下2箇所にパスを通す。
MinGW\bin
MinGW\msys\1.0\bin

dk.rb init, dk.rb installを終えた後に、
Ruby200\lib\ruby\site_ruby\devkit.rb
を書き換える。
$ diff devkit.rb.orig devkit.rb
10d9
<   ENV['PATH'] = 'C:\\online\\Ruby200\\devkit\\bin;C:\\online\\Ruby200\\devkit\\mingw\\bin;' + ENV['PATH']
devkit内のPATH追加を削っただけ。

これでgem install twitterが通るようになった。

token取得

RubyでTwitterのapiを使ってみる - D-ramu blog
twitter側にアプリを登録するまでは上記参照。

自分の環境ではget-twitter-oauth-tokenは上手く動かなかったので、tokenは以下のやり方で取得した。
RubyでTwitterのOAuth認証のアクセストークンを得る手順 - Qiita [キータ]

ssl周り

いざアクセスしようとすると、sslでエラー。
c:/online/Ruby200/lib/ruby/gems/2.0.0/gems/twitter-5.5.1/lib/twitter/rest/client.rb:143:in `rescue in request': SSL_connect returned=1 errno=0 state=SSLv3 read
server certificate B: certificate verify failed (Twitter::Error)
証明書がRubyから見えてないですね。
以下を参考に設置。
igaiga diary(2013-06-17)

api周り

twitterライブラリの仕様もちょくちょく変わってるので注意。

3分でスッキリ! Oauth 1.0図解とRuby Twitter bot開発 | KumanBlog

よく見かけるドキュメントと、configへのアクセスやconfig内のkey名が変わってる。

RTFM。
File: README ― Documentation for twitter (5.5.1)

2014/01/16(木)clは環境変数PATHからインクルードファイルを探さない

メモだけ。

環境はWindows7(64bit), mswin32版Ruby 1.8(ActiveScriptRuby)。

gemで要コンパイルのライブラリ入れるときにコンパイルに失敗する。
c:\online\ruby\lib\ruby\1.8\i386-mswin32\win32/win32.h(31) : fatal error C1083: include ファイルを開けません。'windows.h': No such file or directory
NMAKE : fatal error U1077: 'C:\Windows\system32\cmd.exe' : return code '0x2' Stop.
原因。mswin32版RubyはMS VC++をコンパイルに使用する。コンパイラCL.exeは環境変数"PATH"にINCLUDEファイルのディレクトリを記述していても見に行かない。

初歩的な話だが、ここんとこMS VC++コンパイラ触ってなかったのですっかり仕様を忘れていた。

対策は、環境変数INCLUDEに記述するか、/Iオプションで明記してやる。

gemの中いじるのめんどくさいので、eveで環境変数INCLUDEにディレクトリを追加した。

[参考]
/I (追加インクルード ディレクトリ)

そろそろbundler周りも覚えた方が良さそうだ。

2013/12/28(土)IE8のtable表示バグメモ

かなり以前に書いたメモから起こしてるので、ちょっとおぼろげ。

IE8において、特定の条件下でtableタグのレンダリングに以下の問題が発生する。
問題の内容は、
・表の外枠の上罫線が欠ける
・表の外枠の左罫線が欠ける

先にコードを提示する。
IE8で以下のようなコードをレンダリングすると発生する。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>test</title>
	<style type="text/css">
		table{
			border-collapse: collapse;
		}
		td,th{
			border: solid 1px black;
		}
		div{
			overflow: hidden;
		}
	</style>
</head>
<body>
	<div>
		<table>
			<thead>
			</thead>
			<tbody>
				<tr>
					<td>a</td>
					<td>b</td>
					<td>c</td>
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>
条件は以下の通り。

・ブラウザ: IE8
・モード: 標準モード
・tableの親divで"overflow: visible"以外を指定
・border: collapse
・空のtheadタグがある

必要十分かどうかは不明。

主たる原因は、空のtheadタグがあるから。
これを消すと罫線が表示される。

バグという表現を使ったが空theadは元々validate通らないので、IE8が必ずしも悪いわけではない。ただし他のブラウザで線が欠けるものは発見できなかった。

空theadを使うなと言えばその通りだが、IE対応かつ表の固定ヘッダ(Excelのような)を作ろうとするとsampleなどにもちょいちょい出て来るコードなので多少留意をしておくこと。

2013/11/29(金)エディタ界隈

久々に日本語テキストエディタをさらったので雑なメモだけ。

サクラエディタから乗り換え先を探すイメージで、出来れば機能包含+軽い+ライセンス緩いというのがよい。

まっとうな比較は
比較 - テキストエディタ・スクリーンショット Wiki*
を見てもらうとして。

自分として乗り換えられそうな使用感を得た物だけメモしておく。
フォント周りを調べたときの副産物なのでそこら辺も。

・WZ EDITOR
シェア。ちゃんと進化してた。保有機能はすごいが、インターフェースがちょっと雑然としている。明らかに一太郎になろうとしてるっぽい。フォントを文字コードごとにかなり細かく指定できる。VerUPごとに買うのはちょっと微妙。

・秀丸
シェア。ちゃんと進化してた。高機能だし、うまいことトレンドにシフトしてるとは思うのだが、ほんのちょっとが足りない感じはする。とはいえ最有力。DirectWrite対応でかなり調整できる。複数行正規表現もかなり健康。

・newQX
まさかのQXが新生。さらにまさかの高機能。見た目やI/Fは古臭い。サクラや秀丸のいいところを敢えて無視してる感じ。地味にASCIIだけフォント切り替えにも対応。

・xyzzy
生き残ってた。案外なんでも出来る。オプションが分かりづらい!(笑) Emacsの練習とかによい。地味にASCIIだけフォント切り替えにも対応。

・otbedit
複数行正規表現に強くてフリー。

・Epsaly
・Mery
今後に期待が持てる。

・Sublime Text
新進気鋭がついに3まできた。日本語入力インラインにならないのかな?

・Vim
慣れれば。

・NtEmacs
慣れれば。xyzzyでいいかも。

総合的には秀丸が最右翼。

秀丸がかなり進化しており、サクラの進化が止まってるのでシェアウェア分くらいの差は付いたかも知れない。

WZ EDITORは購入をためらわせる何かがある。整理されてないコンフィグ周りとあのインターフェース、そして何か… 方向性が違う。他と違うI/Fにしてる理由が、改善じゃなくて単に違うことをしたいだけのような……

OtbEditはサクラから乗り換えるのに必要十分な機能を持っている。が、乗り換えるに足る明確な動機がない。

newQXはさすがにインターフェースが古いか。機能面については十分な方向に行きそうだが、もうちょっとインターフェースを何とかして欲しい。

全ての開発・書き物を一本でやれるならVim, Emacsもアリだと思うのだが実際そうではないので慣らすモチベーションが出ない。IDE使ってるし。

ということで、秀丸買うか。

ここに挙がったソフトの動向はある程度注視しつつ併用で。非秀丸ならサクラかOTbEditかxyzzyをその時の気分・用途で。WZは特に秀丸になくWZにある機能が出てきたときにだけ考える。

Vimなー、出来ることと出来ないことを誰かに全部リストアップしてもらえると気軽に移行できるんだけどなあ。

2013/11/29(金)2013年後半のプログラミングフォント事情

以前(4~7年前?)調べたときとだいぶ状況が変わってるようなので久々にさらってみた。

前提はWindows7 64bit、WUXGA(1920x1200)モニタ環境。

日本語入力有りという使用方法を考える。

■結論
以前の調査では、
・IPAフォント類ではJISカバー率が低すぎて無理(これは誤認だった?)
・悔しいけどMSゴシックは悪くない
・とりあえずこだわるならOsakaとか?

うろ覚えだがこんな結論だった。

で、先に今回の結論を書くと、
「よくわからないのでMSゴシックを使おう」

はい、そこ物を投げない。

もうちょっと詳しく書くと、

●gdipp, MacType環境下なら → Ricty
●ClearType(DirectWrite)環境下で、
・ライセンスが怪しくても良いなら → Consolas + MeiryoKE Console(フォント合成)
・それがダメなら → Migu 1M(好みでMigMix 1M, VLゴシック)
●標準アンチエイリアス環境下で、
・記号類が半角表示でも良いなら → Consolas + (MSゴシック or MeiryoKE)(FontLink)
・ライセンスが怪しくても良いなら → MeiryoKEゴシック or MeiryoKE Console
・どれもダメなら → MSゴシック

以下調査。

■レンダリング周り
Windows環境では厄介なことにフォント選びよりもレンダリング環境を先に考える必要がある。
大きく分けて3つ。まあ想像通り一長一短あるわけで。

●標準アンチエイリアス
Windows標準機能。
コントロールパネル -> ディスプレイ -> ClearTypeテキストの調整。
チェックボックスをOFF。

[メリット]
・標準

[デメリット]
・アルゴリズムが悪いのか、ビットマップフォント以外はかなりぼけやすい。視認性が悪い。

●ClearType(DirectWrite)
Windows標準機能。
コントロールパネル -> ディスプレイ -> ClearTypeテキストの調整。
チェックボックスをON。

もしくはDirectWriteを実装したアプリケーションを使う。

[メリット]
・標準アンチエイリアスより視認性が向上することが多い。
・DirectWriteは実装によってはかなり調整可能(秀丸, FireFoxなど)

[デメリット]
・ClearType Tunerの調整範囲ではgdipp, MacTypeより劣る
・標準ClearTypeはサブピクセル描画による偽色をかなり盛るため、背景色によっては目立つ・衝突する
・上記により目が疲れやすくなる可能性あり
・標準ClearTypeは縦方向にアンチエイリアスをかけないため、横線が多い文字(漢字とかだよ!)で恩恵が薄い。

●gdipp, MacType
いわゆるgdi乗っ取り系。

[メリット]
・OS全体に影響
・調整次第だがClearType系よりも綺麗?

[デメリット]
・アプリケーション(独自レンダリングを持つ)によっては反映されない
・アプリケーション(古いゲーム等)によっては文字描画が壊れる
・一部、標準アンチエイリアス環境下で視認性が高かったフォントがかえって悪化する可能性がある
・乗っ取り系なのでおそらくリソースを食う
・gdippはカスタマイズ性低い
・MacTypeはgdippよりカスタマイズ性が高いが、インストーラがadwareだし中国製で英語になりきれてないところがある

[参考]
フォントスムージングの比較 - かえでのWebログ


■フォント
フォントの話に移る。

●欧文
まず、欧文フォントでもっとも趣味に合うのはConsolasだ。視認性が高く、0がslashed、小サイズでも読みやすい。ほとんどの文字で見分けが付く。若干l(半角エル)と1(いち)の見分けがあやしいが、許容範囲内。標準アンチエイリアス下でも高い視認性を誇る。

よってConsolasを軸にする。

Consolasライクな欧文フォントを探すと、
・Consolasオマージュでラインセンスが緩いInconsolata
・#が低いGoogle製Anonymous Pro
・MacのMenlo
・MenloライクなMeslo LG M

あたりを見つけた。ただし、MenloはWindowsに入れようがないので除外。

What are the best programming fonts? - Slant
Top 10 Programming Fonts

これらは日本語フォントとどうにかしてくっつけないといけない。

●日本語
またこれに近い欧文を備えるなり組み込んだりした日本語フォントとして、以下の物を見つけた。
・Ricty
プログラミング用フォント Ricty
・MigMix 1M, Migu 1M
M+とIPAの合成フォント
・VLゴシック
VL Gothic Font Family

M+に不足部分を補う物がトレンド。M+すごい。

最後にライセンスがあやしいメイリオ改造手段と、
MeiryoKe
Windows で見やすくて綺麗なフォント表示 ? MeiryoKe に変更し、MacType で滑らかにする | すぐに忘れる脳みそのためのメモ

さらにそれにConsolasを合成しちまえというもの。もうここら辺はライセンス的にはかなり怪しい。
MeiryoKe_ConsoleとConsolasの合成方法 - GONE WITH THE MEDICINE

●ライセンス
ライセンスを確認する。

欧文ではライセンスが緩い(改造・合成が出来る)のが、Inconsolata, Anonymous Pro, Meslo LG M。詳細は各Webを確認。

日本語系ではM+がまだ字体が足りてないためIPAで補完している物が多く、だいたいがIPAのライセンスに依存。

●欧文フォントの合成方法
欧文フォントはどうにかして日本語とくっつける必要がある。

フォント自体を合成して新しい一つのフォントを作る方法と、WindowsのFontlink機能を使う方法がある。またもや一長一短。

○合成
FontForge
unofficial fontforge-cygwin
等を使用する。

ASCII部(U+0021~U+007e)をはめ込むだけならさして難しくない。が、フォントの特性を理解し、綺麗に、違和感なく仕上げるのは難しい。ビットマップ絡むとさらに難解。先に上げたMeiryoKe + Consolasの合成方法なんかを参照。

合成する方はフォントのライセンスに注意。基本的にOS付属の物はたぶんライセンス×。

○FontLink
FontLinkについては
Windows 7 で日本語フォントを Segoe UI に合わせて調整
FontLink SystemLink の設定値の数字について

を参照。

レジストリをいじって、対象フォントに参照のない文字はリレー方式で次のフォントを見に行くようにする。

結果を確認するのにいちいちOSの再起動が必要。すごくめんどくさい。

Consolasなどの欧文フォントではU+25CF("●")等一部の記号が含まれている。このため、記号等で欧文フォントで描画される物と日本語フォントで描画されるものがあり表示がイマイチになる。"●"は半角、"◎"は全角とか言うことになりかねない。

●評価
自分の評価が高い順に挙げていく。
ただし、どうしても環境依存。
書体記号類一部欧文gdipp/MacTypeClearType標準アンチエイリアスライセンス
Ricty×
Consolas + MeiryoKE Console(フォント合成)○(合成によるズレ)×
Migu 1M(好みでMigMix 1M, VLゴシック)
Consolas + (MSゴシック or MeiryoKE)(FontLink)×○(MSゴシック) ×(MeiryoKE)
MeiryoKEゴシック or MeiryoKE Console×
MSゴシック
Ricty
ConsolasオマージュのInconsolata + Migu 1Mという理想型。
書体そのものは可読性が高く決定版とも言えるようなフォントだが……

実質、gdipp or MacType必須。

Inconsolata自体が標準アンチエイリアス環境下ではアンチエイリアスが強く出てしまう書体のため、Rictyもそれを引き継いでボケボケ・欠け欠けでかなり厳しい。

標準ClearType環境下でもちょっと厳しい。DirectWriteなら調整によっては。

gdipp, MacTypeはデメリットがいくつかあり、これに踏み切れない場合は別のフォントを考える必要がある。

Consolas + MeiryoKE Console(フォント合成)
gdipp, MacTypeでなくともClearType系で十分な視認性を得る。
しかし、二重にライセンスがあやしい。

さらに、合成のやり方次第だが、
・文字の水平位置ずれが生じる
・Consolasが持っていた標準アンチエイリアス下での視認性を失う
等の問題がある。

ライセンスあやしいのはダメという場合、別のフォントを考える必要がある。

Migu 1M(好みでMigMix 1M, VLゴシック)
gdipp, MacTypeでなくともClearType系で十分な視認性を得る。

Consolasよりは欧文書体が好みではない("*"が浮く)。

標準アンチエイリアス下ではアンチエイリアスが強く出てボケボケになる。

ClearTypeの描画が気に入らない場合、別のフォントを考える必要がある。

Consolas + (MSゴシック or MeiryoKE)(FontLink)
Consolas部はビットマップでないはずだが、標準アンチエイリアス下で高い視認性を得る。MSゴシック, MeiryoKEは好み次第。MeiryoKEはゴシックでもConsoleでも。当然ライセンスあやしいのがダメならMSゴシック。

ちなみにMeiryoKEをリンクする場合は横長になる問題が知られている。レジストリの値を好みで、
"meiryoKe_602r1.ttc,MeiryoKe_Console,128,85"

"meiryoKe_602r1.ttc,MeiryoKe_Console,128,100"
などとして、比率を調整した方が良さそうだ。

一部の記号類(ex.U+25CF("●"))がConsolas側に含まれるため半角描画される。この際の挙動はソフトによって違いキャレットの移動も半角に成るケース・全角になるケースと様々。

これが許容できない場合、別のフォントを考える必要がある。

MeiryoKEゴシック or MeiryoKE Console
標準アンチエイリアス下で高い視認性を得る。

0にスラッシュもドットも入っていないので、Oと見分けが付きづらい。

ライセンスあやしいのはダメという場合、別のフォントを考える必要がある。

○MSゴシック
最後に行き着いたのはやはりここ。
標準アンチエイリアス下で高い視認性を…… 得る。

ビットマップを大量に持っているのが強く、やはり100dpi程度までのモニタだとビットマップフォントが光る場面はある。漢字類の罫線の太さの調整はさすが謹製といったあたり。

○おまけ
アプリケーション上でASCII部とそれ以外でフォントを変えられるものがあればそれを使うとよい。Consolas+MeiryoKE(MSゴシック)で幸せになれそう。日本語テキストエディタだと、newQX, WZ EDITOR, xyzzyあたり。もちろん汎用性はナッシング。

●総括
結局自分の使い方だが、M+に期待しつつエディタを選んでソフト合成するか、Consolas+MSゴシック(FontLink)でしのぐといった感じになりそう。DirectWrite調整でRictyが使えないかどうかも継続的に検討してみる。

前回調べたときは発芽レベルだったはずのM+が成長して、日本語プログラミングフォント界隈の幹のようになってきた。M+で足りない文字をどうやって補うかが今のテーマで、その主役がIPA。今後M+が充実してくると、そこも意味のない議論になってくる。これがラインセンス緩いとは…… M+すごい。感謝。

また、Inconsolata, Meslo LG M, Anonymous Pro, Source Code Proと欧文でライセンスが緩く素晴らしいフォントが揃ってきた。後ろ2つはちょっと趣味ではないが、書体そのものは手が足りた感じがある。

なお、以前はOsaka(等幅)を好意的に受け止めていたがOsakaはa,o や 1,lの判別が難しく、プログラミング向きではなかった(そもそもWindowsで使うにはライセンスがダメ)。文章を読むにはいいフォントではある。

Windowsのレンダリングはいまいちだ。古くからある標準アンチエイリアスの品質は致し方なかったにしても、比較的新しいClearTypeで調整幅が少ない。DirectWriteはかなりいじれる感じだが、ClearTypeそのものに手を入れれば良かった気がする……

そんなこんなで、どうしても現時点でのWindows7の世界では、環境を意識して使うフォントを考える必要がある。

標準アンチエイリアスでの見栄えを良くするには、ビットマップを埋め込むか、Windowsの仕様を意識したフォントデザインにする必要がある。当然面倒なので、世のフォント作者はWindowsの標準アンチエイリアスを置いていく。ビットマップについてはIPAが打ち切ったことからも分かるように、切るか極小サイズにのみ残すのが主流のようだ。確かにディスプレイが(特にモバイルで)高精細化していることもあって、ビットマップはどんどん不要になる。M+は一応ビットマップを別配布しているが、これも極小サイズのみのようだ。

今後PCのディスプレイも高精細化するだろうし、Windowsのレンダリングにも手が入るだろう。こういうのはたぶん昔話になっていく。が、目下は何かしら工夫が要る段階だ。

ソフトを作る方からすると、DirectWriteを頑張ってるソフトだけ見た目が優位になる。テキスト周りを扱うソフトが競争やるなら、もうDirectWriteは必須という状況らしい。

そしてMicrosoftがWindows9でテーブルをひっくり返す。この世界ってそういう風に出来てるのよね。

なお、決まり文句ですが全て自己責任でお願いします。
OK キャンセル 確認 その他