2004年09月19日

画像結合ツールの開発 その1

ヤフオクに出品するものの写真の結合をやりながら思う、面倒くせー。
これは明らかに自動化できる作業だ。
で、画像結合ツールを作ると思い立ち、作業に取りかかった。
今回はめずらしくGUIで作る。
いつもは、Perlとかでさっさとやってしまうのに。
まあ、気まぐれだ。
そして、C++Builderを起動してぺこぺこやる。
C++Builderはあまり慣れていないので、少々手こずるけど、GUIアプリを作るのはすごく楽だ。

とりあえず、DrawGridに画像をD&Dして結合するようなIFにしようと思い、DrawGridをいじる。
でも、エクスプローラーからファイルをD&D出来ない。
ドラッグ&ドロップ用のイベントを書いてもうまくできない。
セル同士のドラッグ&ドロップが出来るようになっただけだ。
調べてみると::DragAcceptFiles( Handle, TRUE );とやって、WM_DROPFILESメッセージを処理するようにしないといけないらしい。
メッセージ処理用メソッドを作るにはBEGIN_MESSAGE_MAPを使うらしい。
なんか、MFCみたいだ。
でも、調べてみると、このマクロは単にDispatchに展開されるだけのようだ。
マクロだとデバッグ時にいろいろと面倒なこともあるので、Dispatchは自分でオーバーライドすることにした。
そして、DragAcceptFilesにDrawGridのハンドルを渡しメイク。
カーソルが変わった。
D&D出来るようだ。
で、ドロップ。
・・・
WM_DROPFILESのハンドラに来ない。
なぜ?
って、DrawGridのDispatchにWM_DROPFILESハンドラを書かないといけないんじゃないか。
普通にメインのフォームのやつに書いていた。

DrawGridを継承するコンポーネントを作る。
きちんとWM_DROPFILESハンドラに来るようなった。
次に画像データの保持だが、面倒なのでvectorで10*10決め打ちで作ることにした。ま、ツールだしね。
std::vector > m_Cells; こんな感じ。
そして値初期化の時にm_Cells.reserve(10)とやって作る。当然2次元なので2次元目もreserveし、NULLで初期化。
画像はTJPEGImageで保持させた。
そして、メイクしてインストールしようとしたら、"パッケージ'vcljpg60'にもユニット'Jconsts'が含まれるためパッケージ'dclusr60'は読み込めません。"と出た。
なんだ、コンポーネントでTJPEGImageを使うのはまずいのか?
よくわからん。
じゃ、libjpegを使おうと言うことで、検索。
とりあえず、ここを参考にする。
他にも検索していて、GDI+と言う言葉が目に入った。
そうだ、GDI+を使った方が楽かも。
急遽ligjpegからGDI+に方向転換。
少し調査。

少し時間が空いて、今日。
Cマガを見るとちょうどGDI+の話題だった。
なんと間のいい。
とりあえず購入。

投稿者 Takenori : 10:09 | コメント (0) | トラックバック

2004年10月12日

ボタン絵結合ツール

吉里吉里のボタン絵には通常、押下、選択の3つを横に並べたものが必要だ。
単純に横にくっつけると言うのは、プログラムでは簡単だが、普通のペイントツールを使うとかなり面倒だ。(単純に並べるだけなのに、ドットがずれないかどうかに神経を使う)
ペイントツールでこのような機能を持ったものが存在するかもしれないが、知らないので作ることにした。
仕様は、
フォルダをD&Dすればその中にあるBitmapをすべてくっける。
くっつける時のルールは"名前.bmp", "名前_d.bmp", "名前_s.bmp"と言う名前のファイルを一組として、横にくっつくていく。
くっつけられた画像は、D&Dされたフォルダの下にbuttonフォルダを作り、その中へ"名前.bmp"というファイル名で出力する。
とする。
で、なにげにC++Builderでボタンとテキストボックスをくっつけて、D&Dのハンドラ書いて、FindFirstで"*.bmp"を列挙するところまで作った。
そして、くっつける処理はGDI+でも使ってみようと思い、ヘッダーをインクルードするとエラーが山のように出てくる。
あらら。
すごく行き当たりばったりだが、C#で.Net Frameworkを使い作る方向に変更。
少しC#に興味があったからだ。
で、まずはフォームにボタンやエディットボックスを置く。
でも、これはC++Builderに近いなぁ。
これは意外といいかも。
そして、D&Dの処理を調べる。
テキストをD&Dするサンプルがすぐに見つかったので、それを適当に改造して、フォームに対するドロップを処理するようにしようとするが、よくわからない。
そもそも、C#でプログラムを一度も組んだことがないので、文法などもよくわかっていない。
Cを半音上げたものだから、C#って聞いていたので、Cと似たようなものかなぁと思っていたのだが、それほどすんなりとは行かないようだ。
コードの一部に波線が引かれていたので、カーソルを置くとツールチップで説明が出たが、よくわからない。
C#独特の記法のようだ。
C#入門ぐらいは読まないとダメかな。

今やるのはちょっと面倒臭いなぁと思って、どうしようと考えていたらImageMagick(PerlMagick)を使うことを思い付く。
PerlMagickは使ったことがないけど、これなら簡単に出来そうな気がした。(根拠なし)
で、ImageMagickのページのAPI->PerlMagickを読んで適当に作ってみる。(このページの日本語訳ないかなぁ?)
少し悩むが、意外とあっさり出来た。
次のコードで、'b_fast.bmp', 'b_fast_d.bmp', 'b_fast_s.bmp'の3つファイルを横にくっつけて、x.pngという名前で出力する。

use Image::Magick;

$image = Image::Magick->new;
$x = $image->Read('b_fast.bmp', 'b_fast_d.bmp', 'b_fast_s.bmp');
warn "$x" if "$x";
$p = $image->Append(stack=>'false'); # stack falseでLeft to Rightでくっつける
#warn "$x" if "$x";
$x = $p->Write('x.png');
warn "$x" if "$x";

やはり、PerlMagickは便利だ。これから少しずつ使っていきたいなぁと思う。
それはともかく、ここまで出来れば後はいつも通り書けばいい。
次のような感じ。

use Image::Magick;

foreach( glob('*.bmp') ) {
 if( /.+_d\.[bB][mM][pP]/ ) { next; }
 if( /.+_s\.[bB][mM][pP]/ ) { next; }
 /(.+)\.[bB][mM][pP]/;
 $base_name = $1;
 {
  local($image,$x,$p);
  $image = Image::Magick->new;
  $x = $image->Read($base_name.'.bmp', $base_name.'_d.bmp', $base_name.'_s.bmp');
  if( "$x" ) { warn "$x"; next; }
  $p = $image->Append(stack=>'false');
  if( "$x" ) { warn "$x"; next; }
  $x = $p->Write($base_name.'.png');
  if( "$x" ) { warn "$x"; next; }
 }
}

buttonフォルダは作らないが、pngで出力するようにしたのでかまわないだろう。
PerlMagickを使えば楽勝だったな。

投稿者 Takenori : 12:14 | コメント (5) | トラックバック

2005年01月13日

ImageMagickライブラリのビルド

ImageMagickを使えば、かなり多くのフォーマットに対応できるし、C++での使い方もPerlMagickのように簡単に見える。
また、ライセンスもApache-style licenseで、たぶんオープンもプロプラエタリにも使えるとある。
たぶんと書いてあるのは、リンクするライブラリが多いためだろう。
以上のようなことから、ImageMagickを使いたいと思い、ビルドしてみることにした。
バイナリのインストーラーもあるが、いろいろとインストールされてしまうので、必要な物のみスタティックなライブラリとしてビルドし、必要に応じてリンクするような形態にしたいため、ソースからビルドすることにした。

Install-windows.txtを見ながら進めた。
使用したのは、Windows Source 6.1.8-5で、VCは2003。
まずは、ImageMagick-6.1.8/VisualMagick/configure にあるVCのプロジェクトを開き、Releaseビルドでconfigure.exeをビルド。
出来たconfigure.exeをダブルクリックして起動するとダイアログが開く。
"次へ" をクリックした後、Build type setupでStatic Multi-threaded runtimesを選択。
Use X11 stubs to... のチェックははずした。
Build optionsはGenerate Visual Studio 7 formatにだけチェックが入った状態にし"次へ"をクリック。
次のパスの設定などはそのままにし、完了すると、VisualStaticMT.sln がImageMagick-6.1.8/VisualMagick に出来る。他にも各ライブラリのプロジェクトファイルが生成されたようだ。
VisualStaticMT.sln でVCを起動し、ビルド。
しばらく待てばImageMagick-6.1.8/VisualMagick/libにわんさかライブラリが出来る。
また、ImageMagick-6.1.8/VisualMagick/binに実行ファイルがいろいろと出来る。
Debug版、Release版はそれぞれ、途中のDBとRLの文字が異なるライブラリが生成される。
以上で必要なライブラリは生成されたはず。
次は、簡単なサンプルを作れるかどうか確認する。

投稿者 Takenori : 04:37 | コメント (0) | トラックバック

ImageMagickを使う

以下は、VC 2003で確認した。
まずはVCを起動し、新規プロジェクトでコンソールアプリのプロジェクトを作った。
そして、インクルードディレクトリに ImageMagick-6.1.8/Magick++/lib とImageMagick-6.1.8 を追加。
ライブラリパスを設定に追加し、ライブラリをフルパスで指定しなくても良いようにした。
ライブラリはいっぱいあって面倒なので、次のように入力して一覧が記述されたテキストファイルを作った。
perl -e "foreach( glob(\"*.lib\") ) { if( /DB/ ) { print $_.\" \"; } }" > DB.txt
Release版も同様に次のようにして一覧テキストを作った。
perl -e "foreach( glob(\"*.lib\") ) { if( /RL/ ) { print $_.\" \"; } }" > RL.txt
で、出力されたテキストファイルからプロジェクトの追加ライブラリにコピペ。
Socket関連も使うようなので、Ws2_32.lib も追加ライブラリに追加。
LIBCMTD を無視するライブラリに追加。
以上で、Magick++を使える環境が整ったはず。
サンプルにあった物とほぼ同じ以下のようなソースをビルド。
#include "stdafx.h"
#include <Magick++.h>
#include <iostream>
using namespace std;
using namespace Magick;

int _tmain(int argc, _TCHAR* argv[])
{
 // Construct the image object. Seperating image construction from the
 // the read operation ensures that a failure to read the image file
 // doesn't render the image object useless.
 Image image;

 try {
  // Read a file into image object
  image.read( "test.jpg" );

  // Crop the image to specified size (width, height, xOffset, yOffset)
  image.crop( Geometry(100,100, 100, 100) );

  // Write the image to a file
  image.write( "x.jpg" );
 }
 catch( Exception &error_ )
 {
  cout << "Caught exception: " << error_.what() << endl;
  return 1;
 }
 return 0;
}
で、実行したらException。
調べると、どうやら ImageMagick-6.1.8/config/magic.xml が実行ファイルと同じディレクトリに必要なようだ。
magic.xml をコピーし、実行したらうまくいった。
以上でVCからはImageMagickが使えるようになった。
ちなみに、上記コードの実行ファイルのサイズは3.6MB。やはりでかいな。

投稿者 Takenori : 05:16 | コメント (0) | トラックバック

2005年01月17日

画像を縮小

いままでGIMPを使って1枚1枚縮小していたが、面倒になったので、スクリプトを書くことにした。
で、ImageMagick(PerlMagick)を使おうと思ったが、Perl5.6が入っているマシンだったので、ImageMagickをインストールしてもPerlMagickが動かなかった。
少し悩んだが、コマンドラインツールもついていることを思い出して、コマンドラインツールを呼び出して使うことにした。
初め"-sample"を使ったのだが、どうも汚い。
近傍点を取ってくるだけのようだ。
もう少しリファレンスを調べて"-scale"を発見。
これで綺麗に縮小できるようになった。
で、スクリプトは次のような感じ。

foreach( glob("*.jpg") ) {
  print( "convert -scale 512x384 -quality 80 $_ temp.jpg\n" );
  system( "convert -scale 512x384 -quality 80 $_ temp.jpg" );
  print( "delete $_\n" );
  unlink( $_ );
  print( "rename temp.jpg $_\n" );
  rename( "temp.jpg", $_ );
}
unlink( "temp.jpg" );

同一フォルダにある*.jpgファイルを片っ端から縮小していく。
JPEGのクオリティーは80に設定。

投稿者 Takenori : 01:59 | コメント (0) | トラックバック

画像を縮小

いままでGIMPを使って1枚1枚縮小していたが、面倒になったので、スクリプトを書くことにした。
で、ImageMagick(PerlMagick)を使おうと思ったが、Perl5.6が入っているマシンだったので、ImageMagickをインストールしてもPerlMagickは動かなかった。
少し悩んだが、コマンドラインツールもついていることを思い出して、コマンドラインツールを呼び出して使うことにした。
初め"-sample"を使ったのだが、どうも汚い。
近傍点を取ってくるだけのようだ。
もう少しリファレンスを調べて"-scale"を発見。
これで綺麗に縮小できるようになった。
で、スクリプトは次のような感じ。

foreach( glob("*.jpg") ) {
  print( "convert -scale 512x384 -quality 80 $_ temp.jpg\n" );
  system( "convert -scale 512x384 -quality 80 $_ temp.jpg" );
  print( "delete $_\n" );
  unlink( $_ );
  print( "rename temp.jpg $_\n" );
  rename( "temp.jpg", $_ );
}
unlink( "temp.jpg" );

上記スクリプトでは、同一フォルダにある*.jpgファイルを片っ端から縮小していく。
保存されるJPEGのクオリティーは80に設定。

投稿者 Takenori : 01:59 | コメント (0) | トラックバック

perlでゴミ箱へ

いつもはperlで削除する場合、unlink()で消してしまうが、いきなり消すのではなく、ゴミ箱へ一度入れたいと思った。
で、SHFileOperationが使えたらゴミ箱へ移動出来るはず。
ActiveStateで検索すると、Win32-ShellExtと言うちょうどいいのがあった。
ppm install Win32-ShellExt とやるが、インストールできない。
上述のページを見るとPlatforms: Hpux-ia64 とある。
これってIA64用ってこと?
うーん、他にないのかなぁ。

投稿者 Takenori : 11:51 | コメント (0) | トラックバック

2005年02月11日

SWIGを使ってみる (Perlでゴミ箱へ)

perlでいきなりファイルを削除せずにゴミ箱へ移すために、ゴミ箱へ削除するためのperlモジュールを作ることにした。
で、以前知ったSWIGを使ってみることにした。
マニュアルとサンプルを見てとにかく書いてみる。
まずは、ゴミ箱へ削除する関数を書く。
ファイル名はtoTrashBox.cppとした。

#include <windows.h>
#include <shellapi.h>
#include <string.h>

extern "C" void toTrashBox( const char *p )
{
  SHFILEOPSTRUCT stFile;
  char path[MAX_PATH];

  size_t len = strlen(p);
  strcpy( path, p );
  path[len+1] = '\0';

  memset( &stFile, 0, sizeof(SHFILEOPSTRUCT) );
  stFile.hwnd = NULL;
  stFile.wFunc = FO_DELETE;
  stFile.pFrom = path;
  stFile.pTo = NULL;
  stFile.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
  ::SHFileOperation( &stFile );
}

パスは\0\0で区切らないとならないため、内部でコピーして\0を足している。
後、渡すパスはフルパスでないといけない。
他はたいしたことはやっていない。
次にSWIGスクリプト(?)をW32Shell.iという名前で作る。
中身は次の通り。

/* File : W32Shell.i */
%module W32Shell

extern void toTrashBox( const char *p );

で、コマンドラインでSWIGに渡す。

> swig -perl W32Shell.i

すると、W32Shell_wrap.c と W32Shell.pm が出来る。
次に、W32Shell 用のプロジェクトを作る。
DLLのプロジェクトとして作り、中身は空にする。

C/C++の追加インクルードディレクトリに"C:\Perl\lib\CORE"を追加。
リンカの追加の依存ファイルに"C:\Perl\lib\CORE\perl58.lib"を追加。
これはインストール環境やperlのバージョンによって変わるので、適宜あわせる。
で、プロジェクトにW32Shell_wrap.c と toTrashBox.cpp を追加。
後はビルドすればOK。
W32Shell.dllが出来る。
で、実際に使う場合のperlスクリプトは次のようにする。

use W32Shell;
W32Shell::toTrashBox('C:\test.txt');

これで、C:\test.txt がゴミ箱へ移動される。
もしかしたら需要があるかもしれないので、その内このモジュールは公開するかも。
気ままにメソッドを追加しそうだけど。
と言っても、そんなに使いたい物はないかな?
まあ、欲しくなったときに追加していこう。

投稿者 Takenori : 00:32 | コメント (0) | トラックバック

2005年02月12日

サウンドの再生

sndPlaySound を使えば簡単にサウンドを再生できる。

投稿者 Takenori : 17:41 | コメント (0) | トラックバック

2005年03月27日

PerlMagickでMPEGファイルを作る

use Image::Magick;

$image = Image::Magick->new(size=>'640x480');
for( $i = 0; $i < 25; $i++ )
{
  image->ReadImage('xc:black');
  text = sprintf("%03d",$i);
  $image->[$i]->Annotate(font=>'Century', pointsize=>100, fill=>'green', text=>$text, gravity=>"Center" );
}
$x = $image->Write(filename=>'test001.mpg');
warn "$x" if "$x";

上のPerlスクリプトを実行すると000~024までの数字が表示されるだけのMPEGムービーが出来る。
FPSは25、アスペクト比は1.42 : 1。
FPSやアスペクト比を変更したいが方法がよくわからない。
FPSはまあいいとしてアスペクト比は何とかしたいところ。
とりあえずはTMPGEncでエンコードしなおせば済むが・・・ テスト用ならそれでもいいかな。
後、5分ぐらいムービーを作ろうとしたらテンポラリファイルが作れないと言われ終了。30GBぐらいは空いているんですけど・・・
長いムービーを作る場合は少しずつ作らないとダメそうだな。

投稿者 Takenori : 23:39 | コメント (0) | トラックバック

2005年03月30日

連番画像からMPEGファイルを

PerlMagickでいきなりMPEGを作るのは厳しそうなので、まずは次のようなスクリプトで連番JPEGファイルを作った。

use Image::Magick;
for( $i = 0; $i > 1800; $i++ )
{
  my $image = Image::Magick->new(size=>'640x480');
  $image->ReadImage('xc:black');
  $text = sprintf("%05d",$i);
  print "Create image #".$text.".\n";
  $image->Annotate(font=>'Century', pointsize=>100, fill=>'green', text=>$text, gravity=>"Center" );
  $image->Set(quality=>90);
  $filename = sprintf("img%05d.jpg",$i);
  $x = $image->Write($filename);
  warn "$x" if "$x";
}

で、連番画像からムービーを作るツールを探したのだが、見つからず、自分で作ることを考えていたのだが、TMPGEncで作れることがわかった。
これで、テスト用のムービーが手軽に作れる。

投稿者 Takenori : 22:38 | コメント (0) | トラックバック

2005年11月21日

コード補完マクロ

コピーコンストラクタや演算子などを書いていて煩わしくなってきた。
前に+とか入力した後にマクロを実行すると、operator+などと勝手に補完してくれるようなマクロを書いていた。
けど、どこかへ行ってしまった。
で、再び書く。
今回は、演算子系だけではなく、ヘッダーファイルを作った時に毎回書くようなのも補完してくれるようにした。(ただし、演算子などは全部は作っていない。必要になった時に追加予定)
例えば、"fh"と打った後にマクロを実行すると、ヘッダーファイルの定型文を一気に追加してくれるようなものだ。

要は、カーソルの前にあるコマンドを見て何かをしてくれるマクロだ。
このようにしていれば、マクロの名前を入れたりしなくて済む。
また、マクロにショートカットキーを割り当てればさらにお手軽だ。

演算子で補完する文を宣言にするか定義にするかは悩みどころ。
開いているファイル名を得られるのなら拡張子で判断できるが……
とりあえずは、定義が入るようにした。
消すほうが楽だし。
後、クラス名などは自分で置換しないといけないようになっている。
ある程度解析するようにするか、ダイアログで入力を促すようにすれば出来るけど、そこまでするのもどうか。
ま、ほどほどに省力化できればいい。

ヘッダーの定型文補完は結構便利だ。
ヘッダーコメントやnamespaceなどが勝手に入ってくれる。
ダイアログを表示して、クラス名やnamespace名などを入力できるようにすればもっと楽になるかな?
簡易コードジェネレーターみたいなものだし。

投稿者 Takenori : 20:10 | コメント (0) | トラックバック

2006年04月09日

Perlでオブジェクトを扱う

クラスとかオブジェクト指向とかの話なんだけど、クラスという感じではないし、オブジェクト指向っぽくなくてもいいので、とりあえずオブジェクトを扱うと言うタイトルにした。このタイトルも微妙だけど。
以降、便宜上それはクラスと呼ぶことにする。

それはともかく、時々使いたくなってそのたびに忘れてしまっているのでここにメモしておく。
内容はそんなに確かじゃないかも。

ファイル名とパッケージ名は同じにする。
パッケージ名は単なる名前空間っぽい。詳しくは知らないけど。
ファイル名の拡張子はpmにする。
ファイルの中身は次のような感じ。

package hello;
use strict;
sub new {
    my $className = shift;
    bless {
        Name => undef,
    }, $className;
}
sub setName {
    my $self = shift;
    $self->{Name} = shift;
}
sub print {
    my $self = shift;
    print "Hello ".$self->{Name}."\n";
}
sub DESTROY {
    print "destory.\n";
}
1;

new 関数の名前は何でもいいみたいだけど、new とするのが慣習のよう。
で、この関数の最初の引数にはそのクラスの名前が渡される。
クラスのデータにしたいものを bless 関数でクラスの名前と関連付ける。
bless 関数は出来上がったクラスのインスタンス(?)を返す。
この関数では return が省略されているけど、関数は最後の式の実行結果を返すので、ここでは bless の返り値、つまりクラスのインスタンス(?)が new の返り値になる。
関連付けた後に初期化などしたい場合は、bless の返り値を変数に入れておいて何かして、bless の返り値を入れた変数を return で返せばいい。
bless の第1引数は関連付けたい変数、第2引数はクラス名。
ここでは第1引数にハッシュを渡している。
別にスカラーや配列でもいいけど、クラスのメンバ変数が値1個だけとか、配列になってたりしたら使い辛いので、特に何も考えずにハッシュにしたほうが楽。
効率を重視するのならスカラーや配列のほうが少し速いかもしれないけど、自分の場合ほとんどバッチ処理用にPerl を使うのでそんなに効率は重視しない。CGI とか書く場合には考えたほうがいいかも。
第2引数のクラス名は固定値にしてもいいけど、このクラスを継承したい場合クラス名が変わるので、new 関数の最初の引数で渡される名前と関連付けたほうが良い。
new 関数の中身はそんな感じ。

これからわかるように、perl のクラスは少し変な感じがする。
いくつのかの機能があって、それを組み合わせるとクラスが実現できるって感じだろうか?
クラス以外にも柔軟に対応できそうな気がする。

setName と print 関数はメンバ関数。
最初の引数にはクラスのインスタンスの参照が入ってくる。
ただし、それは new で作ったやつをアローで呼び出した場合。
そうでない場合、例えば hello::print() と呼び出すとそうはならない。この場合は明示的にインスタンスを引数に入れる必要がある。
関数の中身は見たまま。

DESTROY 関数はデストラクタ。

例の中身は以上のような感じ。
で、これを使うには次のようにする。

use hello;
my $helloInst = new hello();
$helloInst->setName( "Kaede" );
$helloInst->print();

特に説明の必要はないだろうから説明は割愛。

投稿者 Takenori : 12:48 | コメント (0) | トラックバック

2007年03月04日

吉里吉里3 Releaser GUI フロントエンド(仮) WSHで

最近は、GUIフロントエンドにHTA ( WSH ) を使うことが多い。
コマンドラインのみでもいいけど、引数を忘れてしまって困ることもあるし、他の人に使ってもらう時などGUIフロントエンドがあったほうがいい。
それと、入力を制限することも出来るし、デフォルト値を入れておくことも出来て楽。
でも、そんなに作るものではないので、HTAの基本的な部分を忘れてしまうのが難点。
てことで、サンプルをこの辺に置いとこうかと吉里吉里3 Releaser用のを作った。
当然だけど、これだけでは動かない。
krkrrel.exe と mingwm10.dll と wxbase26ud_gcc_custom.dll がいる模様。
krkrrel.exe をビルドしなおしたらdll類は何とかなるかもしれないけど、リポジトリから取ってきたものを使ったらそうなっていた。
後、細かいテストはしていません。
たぶん、ちゃんと動きます。

このサンプルはアーカイブファイル名の選択が曲者です。
普通のHTMLのinput type=fileでやっているので、存在しないファイルを選択できません。(笑)
ファイルオープンダイアログで右クリックして、新規作成で適当なテキストファイル作って拡張子を.xp4にしてそれを選べば大丈夫。(大丈夫じゃない気がするけど……)
できれば、名前をつけて保存のダイアログを使いたかったけど、うまく行かなかったので諦めた。
他にアーカイブの作成に時間がかかる場合は、応答がなくなります。
この辺りはちょっとどうかと思われます。
作成時は、標準出力をもらうようにしないほうがいいかもしれません。

HTAは、WSHより制限があり少し使い辛いけど、GUIを作るにはHTAでないと辛い。
ウィンドウサイズは変更できるけど、一瞬デフォルトサイズになってから切り替わるので格好悪いため、サイズ指定は使ってない。うまくやる方法があるのかもしれないけど、知らない。
後、VBScriptでは使えるけど、JScriptでは使えないものがある。(ウィキペディアのVBScriptを参考)
混在可能なので、サンプルでは両方のスクリプトが書かれている。
単に片方で書いてうまく行かなくて、もう片方だとうまく行ったからって理由だけど。(VBScriptもJScriptもあんまり詳しくないのでそうなった)

とりあえず、コマンドに引数渡して終わりなので、HTAのGUIフロントエンドはいつもテキトーです。
CSSとかDOMでがんばれば、見栄えのするものが作れる気はするけど。

投稿者 Takenori : 18:02 | コメント (0) | トラックバック

2007年08月10日

OS終了とサスペンドなどからのレジューム

ソフトを起動したまま Windows が終了された時に備えて、WM_QUERYENDSESSION でも終了前処理をした方が良いようだ。
mixi Alert で終了時にデータを保存しているのに保存できていない時があってなぞだったが、WM_QUERYENDSESSION の対処が必要だったわけだ。

サスペンドなどからの復帰は、WM_POWERBROADCAST で検出できるようだ。
[Win32] システムのサスペンド、レジュームを捕まえたい
サスペンドや休止状態からの復帰でタイマーが狂うことに備えて、レジューム時にタイマーを一度リセットしたほうが安全なよう。

投稿者 Takenori : 13:04 | コメント (0) | トラックバック

2007年08月13日

C++Builder 2007 Update 2

C++Builder 2007 Update 2 が公開されていた。
これによって致命的な不具合が解決される。
例えば以下の二つ。
----
-O1 もしくは –O2 オプションを使用したときにコンパイラがスタックポインタを破壊する。また、最適化を行うべき状況で、コンパイラが最適化しない場合に比べて遅く、肥大した不要なコードを追加する
プライベートの複数のTRect フィールドを持つDelphiコンポーネントを使用したときにC++コンパイラがTRect 構造体のオフセットアドレスのミスマッチを起こす
----
なんというか、これらのバグのせいですごい悩んだんですが。

C++Builder 6 で作っていたツールを 2007 に持ってきて、プロジェクト変換してエラーがきつくなった所を直して、ビルド通って動いたと思ったら、特定の操作でアクセス違反で落ちる。
起動はしてある程度使えるんだけど、落ちる箇所があってまともに動かない。
落ちるところは直した箇所とは別で、C++Builder 6 で作っていたツールはそれなりに使っていたので、不具合とは考えづらかったが、潜在不具合かと思って追った。

落ちる箇所はリストが空のときに std::find( begin(), end(), a ) みたいにやっているところ。
デバッガで追うと、空のリストなのに begin() != end() で、begin() のアドレスにアクセスして落ちてる。
あれ? list が空の時って、begin() == end() じゃなかったっけ? と言うか、今までそのつもりでいつも書いていて何も問題起きなかったが、正確な仕様は把握していなかった。
で、少し調べるも空のときの begin() が返すイテレーターについての記述が見付からなくて、ソースを見ることにした。
見ると同じになりそうなのだが・・・

そこで、確か同じ dinkumware のSTLを使っている VC2005 のソースを見ると、少し違う。
なんかちょっとチェックが増えてる。
で、VC で簡単なソース組んで動かして見ると問題なし。
じゃ、Builder の STL かなと同じように組んで動かすと問題なし。
あれ?
ちゃんと動いた。と言うことは、自分が書いたソースがまずいのか?
メモリ破壊でもしているんだろうか?
今まで普通に使えていたんだが。
で、自分のソースを追うもよくわからない。
どうしたものかと落ちる箇所をデバッガで何度も動かしているとおかしなことに気付いた。
end() の返すイテレーターが指しているアドレスが毎回変わってる。
何かおかしい。

C++Builder 6 のプロジェクトをコンバートせずに 2007 で作って、ソースを追加してビルドして見る。
ちゃんと動いた!
なんだ、プロジェクトのコンバーターがおかしいのか。
が、共有ライブラリを使わないようにしてビルドしたらやっぱり落ちる orz
リンカが悪いのか?
仕方ないので、共有ライブラリを使うようにして、リリースビルド。
そしたら落ちる。デバッグでは落ちない。
使えないじゃないか!
もしかしたら設定で回避できるかと試行錯誤するも回避できず。
2007 使えない。。。パッチ出るまで待とうと思った。

で、今日。
なんとか回避する方法あるんじゃないかと再びトライ。
起動するとアップデートがあるとか出た。
もしかして!
アップデートしてビルド。
直った。
普通に動く。
当たり前のことがうれしい。
良かった。
でも、自分の中で C++Builder 2007 の信頼性がかなり落ちた。
もう、普通に使っても大丈夫かなぁ。

投稿者 Takenori : 23:02 | コメント (0) | トラックバック

2007年10月12日

C++ Builder 2007 Update3

何が修正されたかは見ていないが、大量に修正されている。
で、何気なく気付いたのだが、テンプレートのインライン展開周りが改善されているようだ。
なんか描画が速くなった? と思って、計測したら速くなってた。
テンプレートのインライン展開と最適化 で、C++ Builder 2007 の時は遅いって書いたけど、ほぼ期待通り動くようになっていた。
グラフィック周りはインライン展開を当て込んで作っているので、インライン展開されないと遅い。
今回されるようになって速くなったというか、元々はこれぐらいのはずだったのか。
また、その関係で「常に真です」といった警告も出るようになっていた。
たぶん、これがテンプレートのインライン展開をちゃんと見ている証拠だろう。
今までは出ていなかったと思う。

でも、またコンパイラバグっぽい動きに出会った。
C++Builder 2007 Update 2 のエントリーに書いたのと似たような傾向。
テンプレートクラスと他のクラスを多重継承したクラスのポインタを持っていて、その規定クラスのテンプレートクラスのメンバへアクセスしようとしたらアクセス違反で落ちる。
最小限のコードで再現しようとしたが、再現できず。
メンバに入れれば回避できるかな……

自分のソースが間違ってた

投稿者 Takenori : 16:30 | コメント (0) | トラックバック

2008年01月05日

.svn ディレクトリを perl で消す

追記: subversion の場合、ローカルの作業コピーに対してエクスポートを実行できるので、わざわざ以下のようなスクリプトを使わなくても、ローカルの作業コピーをエクスポートする方が楽で速い。

Subversion からエクスポートすれば、.svn ディレクトリは出来ないけど、ローカルに作業コピーがある時は少々時間がかかるのが難点。
そこで、ローカルの作業コピーを適当なディレクトリにコピーして、そのディレクトリで以下のような perl スクリプトを実行すれば、.svn ディレクトリを消すことが出来る。
CVS の場合も以下のスクリプトを少し書き換えるだけで対応出来る。

use File::Find;
use File::Path;

find( sub { rmtree($_, 1, 1) if (-d $_ and $_ eq '.svn');}, '.');

投稿者 Takenori : 16:55 | コメント (0) | トラックバック

2008年01月09日

ファイル名に出来ない文字をエスケープ

.NET だと、GetInvalidFileNameChars で使えない文字が得られるようだけど、それに相当する API が見当たらない。
と言うことで、使えないと言われている11文字だけエスケープする関数を作った。
以下のような感じ。

void EscapeFileName( std::string& filename ) {
  char* escapechar = "\\/,;:*?\"<>|";
  std::string::size_type n;
  while( (n = filename.find_first_of(escapechar)) != std::string::npos ) {
    filename.replace(n,1,1,'_');
  }
}

使えない文字を "_" に置換するのみ。
Shift JIS だと5C問題でこれじゃダメ。

投稿者 Takenori : 16:25 | コメント (0) | トラックバック

ICU を使う

mlang を動的リンクして使ったら、なぜかリリースビルドで読み込みや書き込みのアクセス違反が出た。
以前は、インポートライブラリを使っていて、特に問題なく動いていたんだが。
と言うことで、ICU を使ってみることにした。

使い方は、ICUの文字コード変換を使いたいのですが... を見ればすぐにわかる。
無駄に動的リンクにしたが、mlang から 1.5時間程度で置きかえれたのですぐ。
後、Windows の Shift-JIS は、windows-31j になるので注意。
それと、変換時に最初のアドレスと、最後のアドレスを指定するが、\0 を含まずに指定しているので、長さを指定しないで std::wstring などに入れるとごみが入る。
その点注意。
まあ、たいしたことじゃないけど、初めミスってて化けた。

でも、よく考えたら、euc-jp 使わないので、WideCharToMultiByte と MultiByteToWideChar でなんとかなった。
icudt38.dll が 10MB とでかいので、結局使わないことになりそう。

投稿者 Takenori : 23:21 | コメント (0) | トラックバック

2008年01月11日

エラーコードを調べる

このエラーコードは何かなと、調べたい時がままある。
だいたい grep とかしていたけど、コマンドラインでエラーコード打ったら返してくれるのがあればいいんだと思って作った。
以下のような感じ。
Windows のエラーと DirectX 9 のエラーコードを文字列にして表示してくれる。
たぶん、DirectX 9が入っていないと起動しない。

#include <stdio.h>
#include <windows.h>
#include <sstream>
#include <string>
#include <dxerr9.h>

#pragma comment(lib,"dxerr9.lib")

int main( int argc, char* argv[] )
{
  if( argc < 2 ) {
    printf( "usage:\n" );
    printf( argv[0] );
    printf( " [error code]\n" );
    printf( "\n" );
    printf( "ex.\n" );
    printf( "whaterror 0x01234567\n" );
  } else if( argv[1] ) {
    std::string    valstr( argv[1] );
    unsigned long  errorCode;
    std::stringstream stream( valstr, std::ios::in );
    stream >> std::hex >> errorCode;

    LPVOID lpMsgBuf;
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL );
    if( lpMsgBuf ) {
      printf( (LPCTSTR)lpMsgBuf );
    } else {
      const char* dxErrStr = DXGetErrorString9( errorCode );
      const char* dxErrDesc = DXGetErrorDescription9( errorCode );
      if( dxErrStr ) printf( "%s\n", dxErrStr );
      if( dxErrDesc ) printf( "%s\n", dxErrDesc );
    }
    LocalFree(lpMsgBuf);
  }
}


他の人に聞くと、エラーコードでググるとか。
そっちのが楽かも。
whaterror.zip に置いておくので、気が向いたら使ってください。
パスが通っているところにおいておくと、すぐに使える。
16進数かどうか判定して、10進数でも使えるともう少し便利になるかも。

投稿者 Takenori : 19:53 | コメント (0) | トラックバック

2008年05月02日

OpenEXR のライブラリ

HDR 画像を格納するためのファイルフォーマットとして、OpenEXR がある。
このファイルフォーマットは、任意のチャンネルをいくつも格納できる柔軟なファイルフォーマットらしい。
ミップマップやレイヤーもサポートするようだ。
他にHDR 画像を格納するファイルフォーマットに hdr ファイルフォーマットがある。
こちらは RGBE で HDR 画像を格納するだけの比較的シンプルな構造。

OpenEXR ファイルの構造は詳しくは調べていないが、読み書きするためのライブラリがオープンソースで存在し、そちらを使えば良いようだ。
ライブラリはこのページにある。
ただ、単純にファイルの読み書きをしたいだけなのに DLL が5個に分かれていて、しかも全て合わせると 2.28 MB とでかい。
いったい何が入っているのか気になり少し見てみることにした。

Half.dll
16ビット浮動小数点を扱うためのクラスライブラリのよう。
HDRI 以外に、最近のビデオカードは16ビット浮動小数点型のサーフェイスを作れるので、それを扱う時に使えるかも。
CPU で処理する場合は普通に float ( 32ビット浮動小数点 ) に変換して処理した方が楽で速いと思う。

Iex.dll
例外やエラー関係

Imath.dll
ベクトルやマトリックス、その他幾何学系
色や色空間の変換など
3D 関係で取り扱う数学関係のもののよう。

IlmThread.dll
スレッド、ミューテックス、セマフォ、スレッドプール・タスク など

IlmImf.dll
ファイルの読み書きなど、上記のもの以外全般。

ソースを見た感じだと以上のような構成のようだ。

後、仕様などを見ていて気付いたけど、これは 3D CG 用のフォーマットだな。
ディフューズ、スペキュラー、アルファ、RGB、Z などチャンネル別に出力しておき、合成方法を変えることで最終イメージを調整するような使い方を想定しているよう。
単に HDR 画像を格納したいだけの用途では少々オーバースペックな感じがする。
ただまあ HDR 画像を格納するのに hdr ファイル と OpenEXR ファイルの2つが主に使われているようなので、オーバースペック な気がしても関係ない。
それに、とりあえずライブラリを使えば読み書きできるので利用するのは楽。

チャンネル別にいろいろと出力しておき、合成方法を変えて複数のイメージを作り出すと言うのは、ゲームでも使えそうな気がしたけど、いろいろ考えるとそれほど用途はなさそう。
実行時に合成してバリエーションを生むと言っても、大してパターンを作れないような。
数が多くないのなら、はじめから全部最終イメージで持っておけばいいだけだし……

投稿者 Takenori : 19:39 | コメント (0) | トラックバック

 
Total : Today : Yesterday :