2008-03-19 :-)
_ 朝ったー
0540 起床。
_ [植松伸夫][大木理沙][ファイナルファンタジー ヴォーカル・コレクションズ I −祈り−]通勤ったー
ファイナルファンタジー ヴォーカル・コレクションズ I −祈り−
FF1 から FF6 の曲に歌詞をつけたアルバムです。ヴォーカルは大木理沙さん。日本語の歌詞はファンタジーの色が溢れていて聴いているとけっこう恥ずかしいです。ゲーム音楽に歌詞をつけるとこうなるんだなあ、くらいに聴いてます。
B00005FNVH
_ [FreeBSD][NetBSD]いよいよ7.0-RELEASE登場! FreeBSDフルコース・2008
「NetBSD フルコース」をやってくれないかなあと思ったけど「カーネル読め」で終わりそう。
_ [まつもとゆきひろ][小飼弾]エンジニアの進化は"アウトプット"にあり! まつもとゆきひろ×小飼弾
「アウトプットの数を増やせば当然叩かれることもある。それをおそれずに、叩かれることに強くなってほしい」(小飼氏)、「アウトプットの多い人ほど、たくさん学ぶことができる。RubyはOSSとして公開し、多くの人から突っ込まれ、叩かれてきたからこそ今の姿がある」(まつもと氏)
いままでアウトプットとは「ただひたすら文章を書く」「ブログを書く」ということだと思ってたけどそうじゃない。ブロガーはそれで良いけど( ブロガーってなに ) プログラマならコードをアウトプットすることが重要なんですね。なんということだ。いまさら気づくなんてなあ。
あわせて読みたい:作品をよく見せるためのお手軽なテクニック集
_ 自動返信のためのボットなんてどうだろうか
客先のひとが外出中なのを知ってるんですがそこで敢えて客先へメールを投げたら「休暇をいただいております以下略」というメールが自動返信されてきました。わざわざ自動で返信するなんてのは、コマンドに対して ack を返すとか ping に対して pong を返すとか HELO に対して 250 を返すとか、そのくらいの意味で使っているのだろうけど E-mail の特性からしてそのような行為は無意味であり計算機とネットワークの資源の無駄使いなのでどうせ無駄にするならいっそのこと返信用メッセージを人工無能に書かせるというのは如何なものか。
_ 得意な言語はなんですか?
計算機関連の文脈で上記のような質問があるときの回答に「日本語」「英語」「クリンゴン語」など自然言語が混ざっているときがあるのだけど、質問者は「自然言語も込みで回答してね」ということを言っているのか、それとも「この文脈ではプログラミング言語を回答するだろ常識的に考えて」としか考えてないのか。たぶん前者。
_ [Exif][JPEG][画像][コードリーディング][がらくた][高林哲]がらくたを読む - exif-touch
http://0xcc.net/attic/exif-touch
JPEG ファイルの mtime を Exif にある mtime に変更します。Exif についてはこちら。
module Exif HEADER_OFFSET1 = 12 <= TIFFヘッダー部 開始位置 HEADER_OFFSET2 = 8
Exif というモジュールにしてます。Ruby では大文字で始めると定数になります。HEADER_OFFSET だと用途が分からないので名前を具体的にしてほしいところですが一発プログラムなのであまり深く考えなかったのでしょう。
  module_function
  def exif_file? (filename)
    exif_header = "\xff\xd8\xff\xe1"          <= SOIマーカとAPP1マーカ
    magic = File.open(filename) {|f| f.read(4) }
    magic == exif_header
  end
Exifに使われるマーカー より引用します。
Exif形式画像の最初の部分は、必ず次のような形式になっています。
SOI Marker が FFD8 で APP1 Marker が FFE1 です。これらのマジックナンバーを見て Exif ファイルか否かを判定してます。return などが書いてない場合は最後に評価した値が関数の戻り値になります。この場合はファイルの先頭 4 バイトにある数値が FF D8 FF E1 と同じならば true が返ります。そうでなければ false が返ります。
  def get_endian (f)
    f.seek(HEADER_OFFSET1)
    data = f.read(2)
    if data == "\x49\x49"
      :little_endian
    elsif data == "\x4d\x4d"
      :big_endian
    else
      raise 'unknown format'
    end
  end
49 49 などの値はなんでしょうか?
TIFF形式の最初の8バイトはヘッダー部です。最初の2バイトはバイト並びの形式を定義しています。0x4d4d:"MM"の場合はモトローラ形式、0x4949:"I I"の場合はインテル形式です。
ここの 2 バイトを見ればエンディアンが分かるようです。ちなみに キヤノン:EOS-1Ds Mark III サンプルイメージ 1 にある画像に対して以下のコードを実行したらリトルエンディアンでした。
File.open( ARGV.shift ){ |f|
  p Exif.get_endian( f )
}
% ./exif-touch portrait.jpg :little_endian
read_directory は IFD : Image file directory を読みます。get_time とあわせて読むと面白いです。
  def read_directory (f, read_ushort, read_ulong)
    n = read_ushort.call(f)         ## ディレクトリーエントリー数
    n.times {                       ## ディレクトリーエントリー数ぶんをなめる
      tag   = read_ushort.call(f)   ## ディレクトリーエントリー 12 バイトぶん
      type  = read_ushort.call(f)
      size  = read_ulong.call(f)
      value = read_ulong.call(f)
      yield(f, tag, type, size, value)
    }
  end
  def get_time (filename)
    time = File.mtime(filename)
    begin
      raise 'not an exif file' unless exif_file?(filename)
      File.open(filename) {|f|
        read_ushort = lambda {|f| f.read(2).unpack('v').first }    ## little endian unsigned 16bit
        read_ulong  = lambda {|f| f.read(4).unpack('V').first }    ## little endian unsigned 32bit
        if get_endian(f) == :big_endian
          read_ushort = lambda {|f| f.read(2).unpack('n').first }  ## big endian unsigned 16bit
          read_ulong  = lambda {|f| f.read(4).unpack('N').first }  ## big endian unsigned 32bit
        end
        f.seek(HEADER_OFFSET1 + HEADER_OFFSET2)
        special_offset = nil
        read_directory(f, read_ushort, read_ulong) {|f, tag, type, size, value|
          special_offset = value if tag == 0x8769                  ## Exif offset
        }
        raise if special_offset.nil?
        f.seek(HEADER_OFFSET1 + special_offset)                    ## オフセット値が示すアドレス
        read_directory(f, read_ushort, read_ulong) {|f, tag, type, size, value|   ## Exif SubIFD を読む
          if tag == 0x9003                                         ## DateTimeOriginal
            curpos = f.pos
            f.seek(HEADER_OFFSET1 + value)
            s = f.read(size) # 2003:01:26 16:37:04
            if /(\d\d\d\d):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)/.match(s)
              year = $1.to_i;  mon  = $2.to_i
              day  = $3.to_i;  hour = $4.to_i
              min  = $5.to_i;  sec  = $6.to_i
              time = Time.mktime(year, mon, day, hour, min, sec)
            end
            f.seek(curpos)
          end
        }
      }
    rescue => e
      STDERR.puts "exif-touch: #{filename}: #{e.message}"
      exit 1
    end
    return time
  end
end
「ヘッダーオフセット」のところにある値の回数ぶんだけ read_directory します。special_offset = value if tag == 0x8769 は Exif Offset(0x8769) を探します。
Exif 形式の場合、IFD0の中にはExif Offset(0x8769)という特殊なタグが必ず含まれています。このオフセット値が示すアドレスには、やはりIFD形式のデーター(Exif SubIFD)が格納されており、ここにカメラの詳細情報等が書かれています。
f.seek(HEADER_OFFSET1 + special_offset) で「オフセット値が示すアドレス」まで読み飛ばします。
次の read_directory で Exif SubIFD を読み、tag 0x9003 と比較します。tag 0x9003 はオリジナル画像が撮影された日時です。その日時による Time オブジェクトを生成しておきます( Time.mktime )。
if __FILE__ == $0
  def fmt (t)
    t.strftime("%Y-%m-%d %H:%M:%S")
  end
日付と時刻を整形します。t はたぶん Time オブジェクトが入ります。strftime で 2008-03-19 18:55:22 のような文字列にします。
ここで分からないのは if __FILE__ == $0 です。__FILE__ にはこのファイル名が入ります。$0 にはこのスクリプトの名前が入ります。両方が異なる場合というのはどういう場合なんでしょうか。
  ARGV.each {|filename|
    if Exif.exif_file?(filename)
      old = File.mtime(filename)          ## ファイルの mtime
      new = Exif.get_time(filename)       ## Exif の mtime
      File.utime(new, new, filename)
      puts "#{filename}: #{fmt(old)} -> #{fmt(new)}"
    else
      puts "#{filename}: not an exif file"
    end
  }
end
メインの処理です。ARGV.each で与えたファイルをすべて処理します。
exif-touch では lambda を使ったコードが面白いです。私は lambda を使ったコードに見慣れてなかったので戸惑いました。まだ慣れてませんが。lambda の壁は高そうです。でもこの壁を超えると世界が変わりそう。









>得意な言語はなんですか?<br><br>方言(例えば、関西弁とか)を記入して<br>様子(回答)を待つとか?w<br><br>まぁ〜ニュアンス的には、Cだぁ〜 Basicだぁ〜<br>が出てくるけど、パソコンを知らない人への<br>質問だともっと色々な回答が出てきそうな予感w