waiei -blog-

その日の出来事を簡単に紹介する日記

蜃気楼の画質向上

2017-05-07-Sun-01:00
※5/7 AM9:00追記あり

こんにちは、A.Cです。
昨日も記事を更新したばかりですが、蜃気楼の拡大時画質向上に成功したので緊急でバージョンアップしました。

蜃気楼1.25

旧バージョン
1.24
※クリックして拡大

新バージョン
1.25
※クリックして拡大

Windows7の時は新バージョンと同様の画質で拡大していたのですが、
Windows8以降かなり画質が落ちていました。

で、Windows10のCreatorsUpdateから画質が復活したという情報を以前から耳にしていたのですが相変わらず蜃気楼の画質が低かったのでそんなことはないのではと思っていました。
ところが、DWMAPIのサムネイル機能のサンプルプログラムをいじっていたら特定条件下に限り画質が向上することがわかりました。

条件とは、 DwmUpdateThumbnailProperties 関数でDWM_THUMBNAIL_PROPERTIESのfSourceClientAreaOnlyをtrueにすることでした。

つまりどういうことなのという話ですが、このフラグを有効にすることで対象のウィンドウのクライアント領域(ウィンドウフレームやタイトルバーを除いた部分)のみを拡大対象にすることができます。
今までの蜃気楼は、ここのフラグをfalseに設定してウィンドウ全体を取得、タイトルバー等を表示しないように位置をずらして表示させていたために今回の画質向上の恩恵を受けられなかったみたいです。(何故ウインドウ全体なら低画質のままなのかは謎ですが)

何故そんな面倒なことをしていたのかというと、ここのフラグを有効にしてもウィンドウ全体が取得されていたためです。
まあ、実際は設定しているのに反映されないわけがないのですが、これはHSPで開発しているのが原因の一つでもあります。

通常であれば、DWM_THUMBNAIL_PROPERTIESのページに書かれている通り、fSourceClientAreaOnlyをtrueにするだけでいいのですが、HSPでは「fSourceClientAreaOnly」が定義されているわけがなく、自分で設定する必要があります。
DWM_THUMBNAIL_PROPERTIESの定義部分のソースは以下のようになっています。
#define DWM_TNP_RECTDESTINATION 0x00000001  
#define DWM_TNP_RECTSOURCE 0x00000002
#define DWM_TNP_OPACITY 0x00000004
#define DWM_TNP_VISIBLE 0x00000008
#define DWM_TNP_SOURCECLIENTAREAONLY 0x00000010
    dwFlags=DWM_TNP_RECTDESTINATION | DWM_TNP_RECTSOURCE | DWM_TNP_OPACITY | DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY
    dim tnProperties,11
    lpoke tnProperties,  0, dwFlags
    lpoke tnProperties,  4, 0
    lpoke tnProperties,  8, 0
    lpoke tnProperties, 12, drawx
    lpoke tnProperties, 16, drawy
    lpoke tnProperties, 20, 0
    lpoke tnProperties, 24, 0
    lpoke tnProperties, 28, crect(2)
    lpoke tnProperties, 32, crect(3)
    poke  tnProperties, 36, 255
    poke  tnProperties, 37, 1       ;0なら不可視
    poke  tnProperties, 41, 1       ;1ならクライアント領域のみ

要するに構造体は連続したメモリにデータを入れたものになるのですが、最後の行に書かれている41バイト目のここが1の時にfSourceClientAreaOnlyがtrueとなります。さて、じゃあこの41バイト目というのはどこから出てくるのかという話ですが、DWM_THUMBNAIL_PROPERTIESのページに書かれている順に定義するので、それぞれの値サイズずつずらして代入していきます。




DWORD dwFlags;0バイト目から4バイト分
RECT rcDestination;4バイト目から4バイト分×4
RECT rcSource;20バイト目から4バイト分×4
BYTE opacity;36バイト目から1バイト分
BOOL fVisible;37バイト目から4バイト分
BOOL fSourceClientAreaOnly;41バイト目

はい、上の赤字部分、BOOL(trueかfalseか)なのに4バイトあります。今までここは1バイトだと思い込んでいたので38バイト目から1バイトを書き換えていたのですが反映されていなかったわけです。わかるかー

とにかくまあ、いろいろいじっていたら上記原因が解明できたので1.25に反映しました。

ちなみにですが、クライアント領域を取得した場合、Aeroの合成部分は黒色になります。
例えばエクスプローラーを拡大対象にした時がわかりやすいと思います。
1.25Aero

タイトルバーが黒くなっています。これはDWMによってウインドウを合成する前の状態を取得しているためなので、対応できません。仕様です。

1.24では合成後のウインドウを取得しているためしっかりと色が付きます。
1.24Aero

大した問題はないと思いますし、画質を落としてまで1.24表示にする必要はないと思いますが、settings.iniを編集することで1.24モードの表示に戻すことができます。詳しくはreadmeを参照してください。

追記:ちょっといじったら黒色問題は対応できたので1.251として更新しました。5/7の9:00以前にDLされた方はお手数ですが再DLをよろしくお願いします。

まあクライアント領域のみ取得とか言ってたのに実際は余計な部分まで取ってたりしたんでそのあたりどうやって消すかいろいろ試行錯誤しましたががが
HOME