カテゴリー別

お絵描き、デザイン

写真、動画関連ソフト

アメーバピグ専用ソフト

ホームページ関連

画像処理

スキャナー用

SEO 関連

お楽しみ

その他

過去ログ

2018年04月19日(木)

Gdiplus 矩形と円の描画、AlphaBlend などの速度を計測してみた

SVG エディター ストローク でたくさん制御点を描画したときに、
重いよーな気がしたので、色々とテストしてみました。

Gdiplus の DrawLine で矩形を描画したときの速度

DrawRect_10 109
DrawRect_20 141
DrawRect_40 219
DrawRect_80 390
DrawRect_160 734
DrawRect_320 1422

例えば 1 行目。
_10 は、10 x 10 ピクセルの矩形を
10000 回描いた場合の時間 (ミリ秒) です。

矩形なので 1 回ごとに、
DrawLine が 4 回呼ばれます。

描画先は、32 bpp の DIB から作成した Graphics。
SetPixelOffsetMode(PixelOffsetModeHighQuality);
SetSmoothingMode(SmoothingModeHighQuality);
な感じ。まぁ、だいたい 2 倍ずつ時間が増えてますね。

次に、Gdiplus の DrawEllipse で円を描画したときの速度

DrawCircle_10 187
DrawCircle_20 297
DrawCircle_40 500
DrawCircle_80 718
DrawCircle_160 1297
DrawCircle_320 2313

やはり、DrawLine と似た傾向ですが、
やや複雑な分、ちょっと時間がかかりますね。

で、何度も描く、(小さな) 図形の場合は
画像にしておいて、アルファブレンドしたら
速くなるのか、テストしてみます。

AlphaBlend_10 109
AlphaBlend_20 110
AlphaBlend_40 156
AlphaBlend_80 281
AlphaBlend_160 781
AlphaBlend_320 2609

こちらは画像を全部参照するので、
長さが 2 倍になると処理量は 4 倍になります。

320 > 160 は 1 / 4 に近いといえなくもないですが、
それ以外では、全然 1 / 4 になってません。

小さい画像を AlphaBlend する場合は、もっと速くていいはず。
なので、適当に書いた自前の AlphaBlend でテストしてみます。

OwnAlphaBlend_10 0
OwnAlphaBlend_20 32
OwnAlphaBlend_40 141
OwnAlphaBlend_80 531
OwnAlphaBlend_160 2172
OwnAlphaBlend_320 8609

やはり、_10 とか _20 だと速いですが、
逆に、80 以上では、遅いです。

AlphaBlend はセットアップに時間がかかる一方、
データー処理は高速になるような方法を使ってますね。

グラフィックスカードの機能を
使ってるのかもしれません。

ま、そんなわけで、比較的小さな画像を
別の画像に合成するには、自前の
AlphaBlend で描くのが速そうです。

・・・

一応、勘違いのないように補足しときます。

「小さい画像をたくさん描く場合、
グラフィックスカードの描画を使わない方が速い」

ような結論に見えますが、そうじゃないです。

AlphaBlend ではおそらく
グラフィックスカードの何らかの初期化と
クリーンナップが毎回行われているため遅くなっているだけです。

通常、グラフィックスカードの機能で画像を描く場合、
初期化、描画、クリーンナップの指示をした後で
一気に処理するため、初期化の時間はあまり影響しなくなります。

なので、グラフィックスカードの性能をきちんと引き出せば
普通は、CPU による処理より、速くなります。

ま、あくまで一般論ですけど。

・・・

あ、あと、同じ画像を何回も参照してるから、
CPU のキャッシュが、よく効いてます。

違う画像を次々に描く場合は、
もっと、遅くなるでしょうねー。

ストローク
ストローク ダウンロード
ストローク サンプル画像
ストローク 更新履歴
ご意見・ご要望連絡窓口


2018年04月03日(火)

WinMain から gtest する方法

SVG エディター ストローク の単体テストは
別のプロジェクトでビルドしていたのですが
二度手間がひどいので統合しました。

ストロークはウィンドウアプリケーション、
一方、単体テストは、gtest を利用しているので
コンソールアプリケーションになります。

作成するアプリケーションのタイプが違うので
別のプロジェクトに分けるのが自然ですが、
無駄に手間がかかるので統合しました。

プロジェクトを分けると、
.cpp や .h ファイルをそれぞれに
追加する必要があって面倒なうえ、
それぞれのプロジェクトで同じファイルを
コンパイルすることになるので時間もかかります。

単体テストとアプリケーションの両方から使う
共通のコードを、まとめた DLL、もしくは lib
を作成するプロジェクトを新たに作成し、
リンクする方法もありますが、
それはそれで面倒です。

なので、一つのプロジェクトを使い、
コンパイルオプションによって
生成されるアプリケーションを
分けることにします。

基本的には、

#define TEST_MODE

#ifdef TEST_MODE
#else
#endif

的なコードで、コンパイルする
コードを分岐していきます。

で、最初に、_tWinMain と _tmain を
コンパイルオプションで切り替えてみたのですが、

error LNK2019: 未解決の外部シンボル _WinMain@16 が関数 ___tmainCRTStartup で参照されました。

的なエラーになってダメでした。

コンパイルオプションを変えればいけそうですが、
新しいビルドの構成とかするのは、面倒なので却下デス。

しょうがないので、入り口は、_tWinMain のままいきます。

コンソールアプリ用のコマンドライン引数

コマンドライン引数は、 __argc, __argv, __wargv
を使えば OK なので簡単です。

ただし、ユニコードアプリの場合は、
__argv は NULL になるので __wargv を使いましょう。

コンソールを用意する

あとは、コンソールを用意します。

自分のコードを見ると、 AttachCondole に失敗した場合、
AllocConsole してます。たぶん、コンソールからアプリを
起動したときのことを想定してるっぽいです。

で、成功したら、_fileno(stdout) とかが負の場合
freopen_s してます。ファイル名は、CONOUT$ です。

ちなみに、stderr のファイル名は、CONOUT$
stdin のファイル名は、CONIN$ みたいです。
↓ ま、こんな感じです。

if (_fileno(stdout) < 0)
  m_stdout.Reopen("CONOUT$", "w", stdout);
if (_fileno(stderr) < 0)
  m_stderr.Reopen("CONOUT$", "w", stderr);
if (_fileno(stdin) < 0)
  m_stdin.Reopen("CONIN$", "r", stdin);

↑ の自分のコードですが、
そのままはコンパイルできないので、
てきとーに、freopen_s にでも
書き替えてくださいな。

AttachConsole とか、AllocConsole に成功してる場合は、
プログラム終了前に FreeConsole する必要があるみたいですね。

あ、コンソールに日本語を出したい場合は、

std::wcout.imbue(std::locale("", std::locale::ctype));
std::wcerr.imbue(std::locale("", std::locale::ctype));

とかした方がいいかもね。

gtest の呼び出し

あとは、普通に gtest を呼びだせば OK です。

::testing::InitGoogleTest(&__argc, __wargv);
int ret = RUN_ALL_TESTS();

ま、こんな感じか。

ストローク
ストローク ダウンロード
ストローク サンプル画像
ストローク 更新履歴
ご意見・ご要望連絡窓口


2018年02月27日(火)

StackWalk64 が何故かおかしな値しか返さない不具合の修正方法

だいぶ前にコーディグした
スタックトレースを取得するコードが
うまく動いていなかったので修正しました。

スタックトレースは、 StackWalk64 が 非0 を返すまで呼べば
取得できるのですが、何故か 1 コか 2 コしか返さないうえ、
関数名を取得してみると、よくわからないものが入ってます。

コードにおかしなところが無さそうだったので、
サンプルコードでも探してみようと思って
検索をかけてみると、原因がわかりました。

StackWalk64 の使い方はココ にあります。
英語ですが、読めば使い方がわかると思います。

で、StackWalk64 がおかしな値を返す原因は、
カレントスレッドのコンテキストの取得に、
GetThreadContext を使っているところにありました。

GetThreadContext をよく読むと確かに、
「GetThreadContext をカレントスレッドに対してコールすると、
 成功しますが、得られるコンテキストは、無効です」
とありますね。

・・・

なんでやねん。そんな仕様あるかよ^^。

で、ココ にあるように、Win32 ではアセンブラのコード、
x64 では、RtlCaptureContext を使うことで、
正しいアドレスが取得できるようになりました。

・・・

ちなみに、スタックトレースというのは、
関数呼び出しの入れ子情報のことです。

例えば、main 関数から a() を呼びだし、
a() の中で b() を呼びだしたときの
スタックトレースは、main > a > b
みたいな感じになります。

スタックトレースはデバッガーで
停止すれば見られるのですが、
スタックトレースをコードで取得すると
ログに吐いたり、ある時点でのトレースを
後から見たりできて便利です。

ちなみに、今回スタックトレースを使いたくなったのは、
ログにスタックトレースを吐きたかったからです。

具体的には、 ローカルブラウザ の閲覧履歴に変更があったときの
デバッグ用のログに、スタックトレースも出力することで
デバッグしやすくしました。

ローカルブラウザ は自分のパソコンに保存した
html や xml を開きやすくしたウェブブラウザーです。

気になる方は、試してみてくださいね!

ローカルブラウザ
ローカルブラウザのダウンロード
ローカルブラウザの更新履歴
ご意見・ご要望連絡窓口


2018年02月16日(金)

c、c++ 浮動小数点の計算に注意

写真閲覧ソフトのミルノ PC フォトフレーム
の新機能の実装がだいたい終わったので、テスト中です。

写真をミルノに!

で覚えてね。キラーン。

今日、直した不具合で次のようなものがありました。

double speed = speedPerSec / refreshRate;

speeedPerSec と refreshRate は DWORD 型です。
わりと、やりがちですが、
初心者だと、はまる可能性ありです。

上の式は一見 speedPerSec が 1
refreshRate が 2 だと、
speed に 0.5 が入りそうですが、
結果は 0 です !

何故 0 になるかというと、
speeedPerSec と refreshRate は DWORD 型なので、
DWORD 型の割り算が行われた後で、
double 型に変換される仕様だからです。

もちろんプログラミング言語の仕様によっては、
0.5 になる場合もありますが、c、c++ では、0 です。

こういうのは、プログラムの式を
数学の式と同じように考えていると
気付かないので注意が必要です。

修正するには、

double speed = speedPerSec;
speed /= refreshRate;

とか、

double speed = (double)speedPerSec / refreshRate;

のようにします。

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

x64 の最新版はこちらのページから、ダウンロードできます
Download the latest version of Miruno PC Photoframe x64 here.

・・・

月額会員専用のx64 版 もあります。
月額会員には、こちらのページから参加できます

経験をつむと、間違いの頻度もおちるし、
間違いにもすぐ気付くようになりますが、
間違わないようにはなりませんなぁ。残念!

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年01月19日(金)

7z.dll を使ってみる段階は完了しました

7z.dll を使って書庫を解凍してみるテストが完了しました。

安定して使えそうな感じでなので、
使いやすくラップする作業に入りました。

真面目にやると大変ですが、
使う API しかラップしないので
そんなに、かからないでしょう。

ちなみに、ラップとは
サランラップをかけること
と似たようなもんで、かけると
食材をつかんでも汚れなくなるので安心です。

やっぱ、違うか。

ま、雰囲気は似ていて、直接さわるよりも
使いやすくなるようにします。それがラップ。

当然、うまくやらないと、
使いにくくなるだけなので意味ないです。

7z.dll の場合、COM なので、
ATL の CComPtr を使うと
かるくラップできます。

私の場合、エラー処理のコードを隠したいので、
HRESULT 値がおかしいときは例外を
投げるようなコードでさらにラップします。

ちなみに、PROPVARIANT のラッパーも
ATL/WTL にないみたいなので自前でラップしてます。

・・・

話は変わりますが、7z.dll を ATL で扱うには

struct __declspec(uuid([GUID])) IArchiveOpenCallback;

みたいな宣言が必要です。上の疑似コードは、
IArchiveOpenCallback の GUID として
[GUID] を紐付けます。

error C2787: 'IArchiveOpenCallback':
このオブジェクトに関連付けられた GUID はありません。

みたいなエラーになったら宣言してあげましょう。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年01月18日(木)

7z.dll を用いた zip の解凍に成功しました

前回に引き続き、7-Zip API のテスト中。

今日は、7z.dll を使って zip ファイルを
解凍してみるテストが完了しました。

IStream もどきの COM インタフェースを
備えたオジェクトポインターを渡す必要がありますが、
IStream をラップすれば、難しくはありません。

COM に精通してればの話ですが・・・。

ただし、7z の IInStream の Read 実装で、
IStream の Read の返り値をそのまま返すのは
よろしくないようです。

というのも、IStream ではファイルの末尾に逹っした場合
返り値として、S_OK の代わりに S_FALSE が返りますが、
7z の IInStream では、その場合も S_OK を期待しているからです。

・・・

書庫ファイルのフォーマットを推定するやり方も
だいたい、目処がたったので、もうそろそろ
使ってみる段階は終わりかな。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年01月16日(火)

7-Zip (7z.dll など) を、VisualStudio 2015 でビルドしてみました

今日は、タイトルの通り、7-Zip
VisualStudio 2015 でビルドしてみました。

結論からいうと、 ココ にある通りの方法で OK でした。

簡単に書くと、VisualStudio をインストールするとできる
コンパイル用のコマンドライン環境で、CPP¥7zip に移動し、
namke すれば OK なのですが、そのままだとエラーがでるので、

CPP¥Build.mak の、-OPT:NOWIN98 を削除します。

リンク先のように、
NEW_COMPILER=1
すると、
-GS- オプションと、
-Zc:forScope オプション
がはずれるので、指定した方がよいでしょう。

-GS- は、バッファーオーバーランの検出がオフにするオプションです。
7-Zip にバグがなければ無関係ですが、指定しなくてよいでしょう。

-Zc:forScope は、for の初期化子で定義された変数が
for ブロックの外に出ないようにするオプションだと思います。
VC の昔のバージョンだと既定でブロックの外から
参照できていたのでそれ用でしょう。別にエラーにならないので
あっても困りませんが、指定しなくてよいでしょう。

もう一つのコマンドライン引数の、MY_STATIC_LINK=1 ですが、
指定するとコンパイルオプションの -MD が -MT になるようです。

利用する側のプログラムをコンパイルするときに、
構成プロパティ > C/C++ > コード生成 の
ランタイムライブラリーで、「マルチスレッド DLL」のかわりに、
「マルチスレッド」を選択している人は、指定しましょう。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2018年01月04日(木)

「このファイルを開く方法を選んでください。」で表示されるプログラム名

写真閲覧ソフトのミルノ PC フォトフレーム を修正中。

写真をミルノに!

で覚えてね。キラーン。

まぁ、だいたいテストも終わったので、
x64 版のインストーラーを作成中です。

ミルノ PC フォトフレームをインストールすると、
画像ファイルの既定のプログラムとして設定できます。

その副作用として、ミルノをインストールした後、
エクスプローラーから Jpeg などの画像ファイルを開いた場合、
「このファイルを開く方法を選んでください。」
画面が表示される場合があります。

「このファイルを開く方法を選んでください。」

で、x64 版 (64 ビットバージョン) と
x86 版 (32 ビットバージョン) を
両方ともインストールした場合、
表示される名前が、どちらも、
ミルノ PC フォトフレームだと
好みの方を選択するのが困難です。

そこで、64 版の名前を
「ミルノ PC フォトフレーム x64」
と表示されるようにしました。

結論から言うと、
「このファイルを開く方法を選んでください。」
画面で表示されるプログラム名は、実行ファイルの
「ファイルの説明」か「製品名」なので、
それらを変えれば OK です。

リソースファイル (.rc) でいうと、
"FileDescription" か "ProductName" です。

まぁ、どちらか使われてるんだと思いますが、
自分は、両方とも同じ値にしちゃってるんでわかりません。

ところが、最初、プログラムの上記値を変えても、
表示される名前が変わりませんでした。

たぶん、OS にキャッシュがあるんだろうと思って
調べたみたところ、レジストリの下記場所に
プログラム名のキャッシュを発見しました。

コンピューター¥HKEY_CLASSES_ROOT¥Local Settings¥Software¥Microsoft¥Windows¥Shell¥MuiCache
コンピューター¥HKEY_CURRENT_USER¥Software¥Classes¥Local Settings¥Software¥Microsoft¥Windows¥Shell¥MuiCache
コンピューター¥HKEY_USERS¥[おそらくログインユーザーのID]¥Software¥Classes¥Local Settings¥Software¥Microsoft¥Windows¥Shell¥MuiCache
コンピューター¥HKEY_USERS¥[おそらくログインユーザーのID]_Classes¥Local Settings¥Software¥Microsoft¥Windows¥Shell¥MuiCache

上の 4 つの場所に発見しましたが、
1 つを消すと全て消えたので実体は同じものでしょう。

名前が「実行ファイルのパス + .FriendlyAppName」で、
値が「表示名」になってるようです。

で、今回の場合は、値の名前が、
C:¥Program Files¥SSSoftware¥Miruno2_64¥Miruno.exe.FriendlyAppName
のを削除すると、めでたく新しい名前が表示されました。

・・・

x64 (64 ビット) バージョンの公開はまだ先ですが、

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

ご意見・ご要望はこちらからどうぞ
You can contact me by this mail form.

・・・

今年もよろしく。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2017年12月29日(金)

ミルノ PC フォトフレーム x64 (64 ビットバージョン) のインストーラー作成など

写真閲覧ソフトのミルノ PC フォトフレーム を修正中。

写真をミルノに!

で覚えてね。キラーン。

まぁ、だいたいテストも終わったので、
x64 版のインストーラーを作成中です。

インストーラーは Windows Installer XML (WiX)
と呼ばれるもので作成してのですが、
ちょっとはまったのでメモしときます。

はまったのは、以下の点。

多言語に対応する場合、light でリンクするときに
各国語用の文字列を定義した、wxl ファイルを入力します。

当然、ソフトウェアの名前は、
言語ごとに違うので、wxl で定義します。

で、64 ビットバージョンと
32 ビットバージョンで名前を変えるには、
wxl で変えるのが自然なので、
条件分岐しようとしたところできませんでした。

wxs ファイルでは <?if $(sys.BUILDARCH) = x64 ?>
みたいな感じで分岐できるのですが、wxl では無理です。

何か方法が無いかと思って
探してしまったのが運の尽き。

おそらく、簡単な方法はなさそうです。

wxl ファイルは各国語用の
文字列を用意するためのものなので、
プログラマーでなくとも書いたり読んだりできるように
条件分岐などの複雑な命令は使えない設計なんだと思います。

非常に正しいです。

では、どうすればよいかというと、
wxl では単純に 32 版用の名前と
64 版用の名前を両方定義しておいて、
参照する側で分岐します。

<?if $(sys.BUILDARCH) = x64 ?>
<?define ProductName = "!(loc.ProductName64)" ?>
<?else ?>
<?define ProductName = "!(loc.ProductName32)" ?>
<?endif ?>

wxs 側のコードは、こんな感じっすね。

・・・

x64 (64 ビット) バージョンの公開はまだ先ですが、

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

ご意見・ご要望はこちらからどうぞ
You can contact me by this mail form.

・・・

ちなみに、light に -d オプションを使うと、
変数を定義できますが、それを使うよりも
上であげた方法の方がシンプルでいいと思いますよ。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


2017年12月22日(金)

Windows API、SECURITY_ATTRIBUTES、bInheritHandle 引数の訳

写真閲覧ソフトのミルノ PC フォトフレーム を修正中。

写真をミルノに!

で覚えてね。キラーン。

SECURITY_ATTRIBUTES の bInheritHandle を訳します。

返されるハンドルを、新しいプロセス作成時に継承するかどうかを
指定する真偽値です。もしこのメンバーが TRUE なら、
新しいプロセスはハンドルを継承します。

ですね。

書いてあるとおりですが、子プロセスを作成した後に
親プロセスで作成したハンドルは継承できませんでした。

まぁ、常識的にはそうだわな。

なので、子プロセスへの通信が 1 回のみの場合は
継承を TRUE にしてハンドルを作成した後、
プロセスを作成すれば、ハンドルがそのまま使えます。

ところが、2 回目以降の通信では、
exe が起動済みなので、そのまま渡せません。

結局のところ、普通にプロセス間通信するには、
DuplicateHandle する必要がありますね。

DuplicateHandle で複製したハンドルを閉じるには ?

ちなみに、DuplicateHandle で作成した
ハンドルは、ターゲットプロセスでのみ
有効なハンドルなので、CloseHandle も失敗しました。

私のプログラムでは、(とういかだいたいそうなるとは思いますが)
種々のハンドルを共有メモリーに置いて通信します。

が、転送先のプロセスで共有メモリーの読み込みに失敗すると
ハンドルも当然、読めません。

ハンドルが読めなければ、もちろん
閉じることもできないので、やはり
送信元プロセスで閉じる必要がでてきます。

DuplicateHandle を読むと、dwOptions に
DUPLICATE_CLOSE_SOURCE を指定することで
ハンドルを閉じることができると書いてあります。

その際のパラメーターは、
hSourceProcessHandle にはターゲットプロセスのハンドルを、
hSourceHandle には複製された、閉じたいハンドルを
lpTargetHandle には NULL を
dwOptions には DUPLICATE_CLOSE_SOURCE を
指定せよと書いてあります。

じゃ、hTargetProcessHandle には
何を指定すればいいねん
と、つっこみたくなりますが、
きっと、何でもよいのでしょう。

・・・

x64 バージョンの公開はまだ先ですが、

日本語の最新版はこちらのページから、ダウンロードできます
You can download the latest version of Miruno PC Photoframe here.

ご意見・ご要望はこちらからどうぞ
You can contact me by this mail form.

・・・

bInheritHandle そんなに便利じゃないな。

ミルノ PC フォトフレーム
ミルノ PC フォトフレームのダウンロード
ミルノ PC フォトフレームの更新履歴
ご意見・ご要望連絡窓口


| 1/5PAGES | >>