(AHK)(AutiHotkey)(DIBの作り方、訂正とか修正とか最適化とか)
前回の記事の → http://d.hatena.ne.jp/morakana/20090513/1242212019
訂正とか修正とか最適化とかです 笑)
まあ 黒色で作って リサイズした後 ToneDIB で 各輝度を持ち上げた方が やっぱ速くね? ということで ToneDIBを採用
指定色が黒色なら ToneDIBはスキップする仕様に
もし 「背景色は 圧倒的に白が多い!」というのなら 白で作って 各輝度を持ち下げてもいいかもね
ついでに Imgctl_RepaintDIB関数も できるだけ最適化
ToneDIBともベンチ対決させたので 出来るだけ効率よくしてみました
今回の ケースをシミュレートして UChar と UInt と UInt64 でも ベンチ対決させてみました
結果を言えば UInt64が一番早かったので それを採用
具体的には 「UCharで6回書き込み」「UIntで2回書き込み」「UInt64で1回書き込み」(結果は全て同じ)の3種を
10000回実行するのに掛かる時間を 5回とって それの 平均値を出しました
結果は UChar : UInt : UInt64 = 1 : 0.44 : 0.28 と 約3倍超えに!
まぁ ループしない限り 体感時間は変わりませんけどなにか? 笑)
訂正とか修正とか最適化とかです 笑)
まあ 黒色で作って リサイズした後 ToneDIB で 各輝度を持ち上げた方が やっぱ速くね? ということで ToneDIBを採用
指定色が黒色なら ToneDIBはスキップする仕様に
もし 「背景色は 圧倒的に白が多い!」というのなら 白で作って 各輝度を持ち下げてもいいかもね
;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; imgctl_NewDIB(NewWidth, NewHeight, R, G, B) 新規にDIBを作成して hDIBを返します ;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; 横:NewWidth 縦:NewHeight のサイズで 新規に DIBを生成します ; R G B に 輝度を設定する事で 塗りつぶす色を設定する事が出来ます ; ; BMPファイルのイメージを生成して MtoDIBに渡すことで DIBを生成しています ; 生成に成功すると DIBのハンドルが、 失敗すると 0が返ってきます Imgctl_NewDIB(NewWidth, NewHeight, R = 0, G = 0, B = 0) { BinDataImage := "0x42,0x4D,0x3A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" VarSetCapacity(buf, 58, 0x00) Loop Parse, BinDataImage, CSV NumPut((A_LoopField + 0), buf, (A_Index - 1), "UChar") If !(hNewDIB := Imgctl_MtoDIB(&buf, 58)) Return 0 If ( !R and !G and !B and Imgctl_ResizeDIB(hNewDIB, NewWidth, NewHeight) ) Return hNewDIB If ( Imgctl_ResizeDIB(hNewDIB, NewWidth, NewHeight) and Imgctl_ToneDIB(hNewDIB, R, G, B) ) Return hNewDIB Imgctl_DeleteDIB(hNewDIB) Return 0 } ;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; BOOL ToneDIB(HDIB hDIB, short rMove, short gMove, short bMove) Imgctl_ToneDIB(hDIB, rMove, gMove, bMove) { Return DllCall("imgctl.dll\ToneDIB", "UInt", hDIB, "Short", rMove, "Short", gMove, "Short", bMove, "Int") } ;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; BOOL ResizeDIB(HDIB hDIB, long lWidth, long lHeight) Imgctl_ResizeDIB(hDIB, NewWidth, NewHeight) { Return DllCall("imgctl.dll\ResizeDIB", "UInt", hDIB, "Int", NewWidth, "Int", NewHeight, "Int") } ;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; HDIB MtoDIB(const void *pBuffer, DWORD dwBufSize) Imgctl_MtoDIB(pBuffer, BufSize) { Return DllCall("imgctl.dll\MtoDIB", "UInt", pBuffer, "UInt", BufSize, "UInt") } ;---------------------------------------------------------------------------------------------------------------------------------------------------------
ついでに Imgctl_RepaintDIB関数も できるだけ最適化
ToneDIBともベンチ対決させたので 出来るだけ効率よくしてみました
;--------------------------------------------------------------------------------------------------------------------------------------------------------- ; BOOL RepaintDIB(HDIB hDIB, const REPAINTINFO *repis, DWORD dwRepaintNum) ; ; 注意 : REPAINTINFO を 文字列で設定するように変更しました ; ; 白 を 黒 に 置き換える場合は "255,255,255-0,0,0" と書きます ; 16進数表記でも表記可能です "0xff,0xff,0xff-0x0,0x0,0x0" ; ; 色の置き換えを複数個指定したい場合は | で区切ります ; 白 を 黒 に 黒 を 緑 に 赤 を 青 に 置き換える時は ; "255,255,255-0,0,0|0,0,0-0,255,0|255,0,0-0,0,255" と書きます ; Imgctl_RepaintDIB(hDIB, RepaintInformation) { Num := 0 Arr := 0 Loop, Parse, RepaintInformation, | { Num += 1 Loop, Parse, A_LoopField, - { Loop, Parse, A_LoopField, CSV { Arr += 1 [%Num%][%Arr%] := A_LoopField } } Arr := 0 } VarSetCapacity(RI, (Num * 8), 0x00) Loop, %Num% { Offset := (A_Index - 1) * 8 NumPut(([%A_Index%][6] << 48) + ([%A_Index%][5] << 40) + ([%A_Index%][4] << 32) + ([%A_Index%][3] << 16) + ([%A_Index%][2] << 8) + [%A_Index%][1], RI, Offset, "UInt64") } Return DllCall("imgctl.dll\RepaintDIB", "UInt", hDIB, "UInt", &RI, "UInt", Num, "Int") } ;---------------------------------------------------------------------------------------------------------------------------------------------------------
今回の ケースをシミュレートして UChar と UInt と UInt64 でも ベンチ対決させてみました
結果を言えば UInt64が一番早かったので それを採用
具体的には 「UCharで6回書き込み」「UIntで2回書き込み」「UInt64で1回書き込み」(結果は全て同じ)の3種を
10000回実行するのに掛かる時間を 5回とって それの 平均値を出しました
結果は UChar : UInt : UInt64 = 1 : 0.44 : 0.28 と 約3倍超えに!
まぁ ループしない限り 体感時間は変わりませんけどなにか? 笑)
a := 0x11 b := 0x22 c := 0x33 d := 0x44 e := 0x55 f := 0x66 VarSetCapacity(buf, 8, 0x00) tt := 0 Loop, 5 { tc := DllCall("kernel32.dll\GetTickCount") Loop, 10000 { NumPut(a, buf, 0, "UChar") NumPut(b, buf, 1, "UChar") NumPut(c, buf, 2, "UChar") NumPut(d, buf, 4, "UChar") NumPut(e, buf, 5, "UChar") NumPut(f, buf, 6, "UChar") } tt += (DllCall("kernel32.dll\GetTickCount") - tc) } MsgBox,% tt / 5 tt := 0 Loop, 5 { tc := DllCall("kernel32.dll\GetTickCount") Loop, 10000 { NumPut((c << 16) + (b << 8) + a, buf, 0, "UInt") NumPut((f << 16) + (e << 8) + d, buf, 4, "UInt") } tt += (DllCall("kernel32.dll\GetTickCount") - tc) } MsgBox,% tt / 5 tt := 0 Loop, 5 { tc := DllCall("kernel32.dll\GetTickCount") Loop, 10000 { NumPut( (f << 48) + (e << 40) + (d << 32) + (c << 16) + (b << 8) + a, buf, 0, "UInt64") } tt += (DllCall("kernel32.dll\GetTickCount") - tc) } MsgBox,% tt / 5