自分用のプログラムをいろいろ書いてるのなかで、気がついたことを記しています。
GPX Loggerで記録したGPXデータは、KMLに変換することで、一般的なHTMLと同様に公開することが可能となる。 KMLの公開は、apacheの設定ファイルで下記のようにMIME typeを宣言すれば可能だが、 表示するためには、クライアントとしてGoogle Earthが必要となる。これは少し敷居が高い。
# apacheの設定 AddType application/vnd.google-earth.kml+xml .kml AddType application/vnd.google-earth.kmz .kmz
だが、Googleではブラウザのプラグインも用意しているため、サーバ側にJavascriptを記述すれば、 アプリケーションのインストールなしに利用することもできる。以下がKMLを公開するためのHTMLの記述方法。 Googleのサンプルがよく分からず、試行錯誤してやっと完成した。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<script type="text/javascript" src="http://slide.alpslab.jp/scrollmap.js"></script>
<title>Google</title>
<!-- *** Replace the key below below with your own API key, available at http://code.google.com/apis/maps/signup.html *** -->
<script type="text/javascript" src="http://www.google.com/jsapi?key=__Here_is_your_Google_API_KEY"></script>
<script type="text/javascript">
google.load("earth", "1");
var ge = null;
function init() {
google.earth.createInstance("map3d", initCB, failureCB);
}
function initCB(object) {
ge = object;
// ビルディングレイアを表示する
ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS,true);
// 境界(Border)を表示する
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
// 地勢(Terrain)を表示する
ge.getLayerRoot().enableLayerById(ge.LAYER_TERRAIN, true);
// Navigation Controleを表示する
ge.getNavigationControl().setVisibility(ge.VISIBILITY_SHOW);
// ステータスバーを表示する
ge.getOptions().setStatusBarVisibility(true);
// 緯度・経度を指定して移動する。
var la = ge.createLookAt('');
// 緯度 経度 高度 フラグ 向き 角度 範囲
la.set(35.68, 139.76, 500, ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 45, 5000);
ge.getView().setAbstractView(la);
// KMLをLoadする。
google.earth.fetchKml(ge,'http:://url_for_KML_file',finished);
ge.getWindow().setVisibility(true);
}
function failureCB(object) {
alert('load failed');
}
function finished(object) {
if (!object) {
alert ('bad or NULL kml');
return();
}
ge.getFeatures().appendChild(object);
}
</script>
</head>
<body onload='init()' id='body'>
<h1>PAge TITLE </h1>
<div id='map3d_container' style='border: 1px solid silver; width:800px; height: 600px;'>
<div id="map3d" class="map" style="width:800px;height:600px"></div>
</div>
</body>
</html>
createLookAtのパラメータはここ。
こんな感じで要素が並んでいるときに、
<span id='test0'><input type='chexbox' value='hoge0'>ほげほげ0</span><br /> <span id='test1'><input type='chexbox' value='hoge1'>ほげほげ1</span><br /> <span id='test2'><input type='chexbox' value='hoge2'>ほげほげ2</span><br /> <span id='test3'><input type='chexbox' value='hoge3'>ほげほげ3</span><br />Javascriptでループしながらdocument.all('test'+i).displayで表示(inline)、非表示を切り換えると、 たとえば、全部表示の状態からtest0表示、test1非表示、test2表示、test3表示だった場合、test2と3が表示されない。 spanをdivに置き換えて、blockで扱えば正しく表示できた(IE6)。
JPGデータのThumbnailを作るのに、いままではImageMagickパッケージのconvertコマンドを利用していた。 この場合、ファイルサイズからxyのピクセル数を推測し、適当な縮小率をパーセンテージ与えて変換していた。 たとえば、10%縮小なら、convert -sample 10%x10% source.jpg /outdir/outfile.jpgのようにする。
この場合、ファイルサイズからピクセル数を推測しているので、しきい値の設定によっては、サムネイルのサイズが変わってしまう。 実際のピクセル数は、Exifデータで保存されているが、面倒なのでそうしていたが、 結構サイズがバラバラなので、そろそろちゃんとExifのパラメータを参照して一定サイズに揃えようと考えた。
だが、調べてみると、単純にEXIFからThumbnailが作れるコマンドがあるため、そちらを利用すれば一発でできることが判明。
Linux上でExif情報を活用するためには、jheadを利用することが一般的なようだが、 Vine Linuxでは、パッケージが用意されていない。代わりにlibexifを利用した、exifコマンドがある。
ただ、使い方が英語でもよく分からない。google様に聞いても、コマンド名が汎用的すぎてEXIFの説明しか出てこない。 いろいろ試行錯誤した結果、exif -e sourceimg.jpg -o="/dir/outfile.jpg" とすれば良いようだ。スクリプトを変更すると倍ぐらいの速度となった。
プログラムの話とはちょっと違うが。
MySQLをVer 5に変えたのだが、Charsetの指定がめんどくさい。Create Tableで作るときは、Default Charsetを最後にいれるのだが、 入れ忘れたり、複製して作ったときは設定が反映されていない。いちいちalter table changeで設定しなおさないといけない。
その際に、どのfieldがどのCharsetを使っているかを確認する方法。
show full fields from table_name
weblog風(あくまで風)のフォーマッタは一応の完成をみる。とりあえず、perlのHTML系のスクリプトで覚えたことをいかに記す。
use HTML::TreeBuilder;
$tree->parse_file($filename);
$body = $tree->guts(); #$treeをそのままas_HTMLで出力すると、implicitなtag(htmlなど)が挿入されてしまう。
#そのため、最上位をHTML::Elementとして取得。elementifyでも上記と同様。
$body->as_HTML('<>&',"\t",{}); #第一パラメータはエスケープするキャラクタ。指定しないと2バイトコードもエスケープされてしまい不都合
#第二パラメータは、インデントするキャラクタ。指定する必要は無し。
#第三パラメータは、終了タグを無視するモノをハッシュで渡す。{"<dt>"=>1}など。
as_HTMLの第三パラメータを指定しなかった場合は、<p>,<dt>,<dd>が指定されている。
特定のタグ、アトリビュートの変更方法は以下の通り。
foreach $node ($body->content_list()) {
$tags = $node->tag(); #tagの取得
$attr = $node->attr('class'); #アトリビュートの取得
if ($tags eq 'div' && $attr eq 'title') {
$node->delete_content(); そのタグが内包するコンテンツを削除
$node->tag('h1'); タグをh1に変更
$node->push_content(
"テキスト1",['a',{'href'=>"href://to.link.jp/"},"anchartag内のテキスト"],"テキスト2"
)
weblog風(あくまで風)のフォーマッタで、html文書の分析に、HTML::TokeParserを使用している。 ここはそのメモ。CPANで英語をちゃんと読めば必要がないメモだがそれをメモするのが鳥頭クオリティ。
use HTML::TokeParser;
$p = HTML::TokeParser->new('sample.html') || die "Can't Open: $!";
while (my $token = $p->get_token) { # get毎に次のtokenを読み込む
if ( $token->[0] eq 'S' && $token->[1] eq 'div' ) { # タグ形式がSでタグがdivのもの
print $p->get_trimmed_text,"\n"; # テキストを取り出す。ただその下位にもタグがあると取り出せない。
print $p->get_phrase,"\n"; # 下位にもタグがあるときは、get_phraseで取り出す。
}
}
会社で、システムから定期的にメールを送信している。
そのメールを見て作業進捗をwebシステムに入れるのだが、どうせならそのメールにリンクを埋め込みたいと思い、 multipart/alternativeで、htmlメールを出すことにした。
以下が、そのperlスクリプト。
#!/usr/bin/perl
# MIME::Entity, Net::SMTPによりメールを送信するサンプル。
# 動くはずだが、実際に使っているものを支障がないように修正したので、修正でエンバクした可能性はあり。
#
use MIME::Entity;
use MIME::Words qw (:all);
use Net::SMTP;
use Jcode;
$oLine = new Jcode;
$oLine->set("日本語のタイトル",'euc');
$subject = encode_mimeword($oLine->jis,B,'iso-2022-jp'); ## 題名をmimeエンコード
$oLine->set("宛て先",'euc');
$to = encode_mimeword($oLine->jis,B,'iso-2022-jp'); ## 宛て先の日本語をmimeエンコード
$oBase = MIME::Entity->build( ## 本文となるエンティティ
'Type' => 'multipart/alternative', ## multipart/alternative;
'Encoding' => '7bit',
'X-Priority' => '2 (high)', ## X系のヘッダも設定可能
'From' => 'auto-sender <foo%from.this.domain>', ## %は&に置換される。
'To' => '"'.$to.'" <bar%send.your.domain>', ## 同じく上
'Subject' => $title,
);
$oText = MIME::Entity->build( ## alternativeのtext part
'Type' => "text/plain; charset=ISO-2022-JP", ## Content-type
'Encoding' => "7bit",
'X-Mailer' => undef, ## undefにしないと MIME-tools $ver (Entity $ver)
'Data' => "" ## Dataは空で定義しておく。
);
$oHtml = MIME::Entity->build(
'Type' => "text/html; charset=ISO-2022-JP", ## alternativeのhtml pert
'Encoding' => "7bit",
'X-Mailer' => undef, ## 上に同じ。
'Data' => "" ## 上に同じ。ioで上書きするのでなにか書いてもも同じ。
);
$html_head = q( ## htmlで使用するheaderを定義。
<html>
<head>
<title>メールのタイトル</title>
<body>
);
$header =new Jcode($html_head,'euc');
$html_head = $header->jis;
$footer = q( ## メールのフッタを定義。MIME::Entityではsingetureも設定出来るが...
このページのお問い合わせは、下記まで、
http://wwww.from.this.domain/
);
$oLine->set($footer,'euc');
$footer = $oLine->jis;
$ioText = $oText->bodyhandle->open("w"); ## $oTextのメール本文をioとして開く
$ioHtml = $oHtml->bodyhandle->open("w"); ## $oHtml 〃
$oLine->set("■メール本文中の見出し■"); ## 本分作成。io->printを使って本文を作成してゆく。
$ioText->print("\n",$oLine->jis,"\n"); ## Textでは、そのまま
$ioText->print($footer);
$ioHtml->print($html_head,"\n"); ## htmlではhtmlヘッダを付ける。
$ioHtml->print("<h1>",$oLine->jis,"</h1>\n"); ## htmlでは、さっきのタイトルの前後に<h1>を挟んでみる
$footer =~ s/(http:\/\/.*\/)/<a href="\1">\1<\/a>/ ## urlはリンクで囲む
$ioHtml->print("<pre>",$footer,"</pre>\n</body>\n</html>\n");
$ioText->close; $ioHtml->close;
$oBase->add_part($oText); $oBase->add_part($oHtml); ## 作成した本文を、パートとして追加。
@envelope = ('bar-1@send.domain','bar-2@send.domain','bar-3@send.domain'); ## 送信先を配列に入れる。
$from = 'foo@from.this.domain';
$oSMTP = Net::SMTP->new(
'mail', ## SMTPサーバ名
Hello=>"from.this.domain" ## SMTPサーバのドメイン
);
$oSMTP->mail($from); ## 送信元の指定
foreach $send (@envelope) { ## @envelopeに送信。
$oSMTP->to($send);
}
$oSMTP->data();
$oSMTP->datasend($oBase->stringify); ## 送信するメールの本文
$oSMTP->dataend(); ## データの終わり、メール送信
$oSMTP->quit; ## SMTP接続の終了
}
1;
プログラム上の都合で先にインスタンスを定義しておきたい場合もあるでしょう。 そのような、一度エンティティを定義したヘッダを修正するには、headオブジェクトのインスタンスを使うと修正可能。
$oBase->head->mime_attr("Subject" => "New Subject");