|
![]() ![]() ![]() ![]() ![]() | |
昨日、NumLockLock ver.1.44.04βを公開しました。 既報のとおり「監視対象デバイス接続時に通知表示を行う」での通知方法を、文字ではなく、通知領域アイコンを紫をベースとしたものに変えるように変更しました。 さて、48種類ものアイコンを準備するのは大変ですし、作った後にメンテナンスをするのも大変です。そこで、部品となるアイコンの形状のみを定義し、それらを組み合わせて(画像同士をOR演算でマージできるようにしておき)必要なアイコンを動的に生成する仕組みにできないかを考えました。 Windows APIとC++によるプログラミングで、2つ(以上)のアイコンを読み込んでOR演算的に合成する方法をネット検索で調べようとしたのですが、なかなか見つかりません。関連検索結果として、他の言語のことだったり、画像編集ツールの使い方ばかりが出てくる。 …と、そういえば、Windows APIとC++によるプログラミングなのですっかり失念していましたが、プログラミングの方法をAIに聞くというやり方があるんでした。すっかり脳がバックデートしてました。Windows APIとC++を使っていると、生成AIの事を忘れてしまう。 最近の生成AIは大変よくできていて、アイディアの列挙、謝罪文の作成などもできますし、下にあるような「AIがプログラミングする様子を絵にして」と依頼すれば、絵も作ってくれます。 ![]() (なんで、モニタの裏側にソースコードっぽい絵が映っているの?) ![]() なるほど、こんな感じが「しゃなり」なんですね。 と、今回も知らないことを聞いてしまいましたが、プログラミングでも知らないことを聞いてうまくいくのか、試してみることにしました。間違っていたら動かないプログラムが作れるのだから、気軽に試せるということで。 というわけで「2つのLoadImage APIで取得したアイコンハンドルを重ね合わせて、1つのアイコンにし、そのアイコンハンドルを取得する方法」として聞いてみました。重ね合わせる方法はOR演算です。聞く相手は、Windowsについて詳しそうなCopilotが良いかなぁ。教えてAI! Copilotの回答 (一部加工) LoadImage APIで取得した2つのアイコンハンドルを重ね合わせて1つのアイコンを作成するには、Win32 APIの機能を活用する必要があります。以下に実現する方法の手順を示します:
アイコンのサイズが一致している必要があります。同じ幅と高さを持つアイコンを使用してください。エラー処理を適切に行うことで、コードの堅牢性を高めることができます。 コンパイル通りそうなプログラムが出てきましたので、さっそく試してみました。 ……結果から言うと、うまく動きませんでした。AIは堂々と嘘をつくんですよ。どこが間違えているか、AI自身に聞いてみるという手もありますが、まぁ、ちゃんと考えてみたいと思います。 まず、生成AI自身も語っている通り、エラー処理を適切に行えとあります。なので、各API呼び出しでエラーが返ってきていないかを調べると、3番目のGetDIBits()でエラーが返ってきていることがわかります。なぜなら、 BITMAP bmp1;として定義した変数に対し、 (BITMAPINFO*)&bmp1という、無茶苦茶なキャストを行っているからです。構造体へのポインタのキャストですので、バイト列を他の構造体で読みかえる行為となります。BITMAPとBITMAPINFOは全然違う構造体なので、こんなことできるわけがない。 というわけで、この辺りをガラリと書き換える必要があります。ちなみに、アイコンは16色(4bit)なので、1ピクセル当たり0.5バイトとしての書き換えも必要。カラーパレットも16個分必要。そのあたりも書き換えを行っておきます。 BITMAPINFO *pbi; BYTE bi[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 16]; // BITMAPINFO構造体(末尾のパレット情報格納部がかなり特殊)のためのエリア BYTE buf1[16*16/2]; // 4bitカラーの16x16アイコンのピクセルデータ格納エリア // ベースアイコン GetIconInfo(hIcon1, &iconInfo1); GetObject(iconInfo1.hbmColor, sizeof(BITMAP), &bmp1); // ピクセルデータ格納エリアの初期化 ZeroMemory(buf1, sizeof(buf1)); // パレット情報を得るためにデバイスコンテキストを作成 HDC hdc = GetDC(0); HDC hdc_mem = CreateCompatibleDC(hdc); ReleaseDC(0, hdc); HBITMAP hBmpOld = (HBITMAP)SelectObject(hdc_mem, iconInfo1.hbmColor); // BITMAPINFOの準備 ZeroMemory(bi, sizeof(bi)); pbi = (BITMAPINFO *)bi; pbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbi->bmiHeader.biWidth = 16; pbi->bmiHeader.biHeight = 16; pbi->bmiHeader.biPlanes = 1; pbi->bmiHeader.biBitCount = 4; pbi->bmiHeader.biCompression = BI_RGB; GetDIBColorTable(hdc_mem, 0, 16, pbi->bmiColors); // パレットの準備 // ピクセルデータをバッファの読み出し(上下逆転したようなビットマップデータが得られる) GetDIBits(hdc_mem, iconInfo1.hbmColor, 0, height, buf1, pbi, DIB_RGB_COLORS); : :(この辺りはAIのプログラミングが使えるので省略) : // 最終合成結果のビットマップデータからHBITMAPを作成 SetDIBits(hdc_mem, iconInfo1.hbmColor, 0, 16, buf1, pbi, DIB_RGB_COLORS); // 更新済みビットマップを使用し新しいアイコンハンドルを作成 HICON hNewIcon = CreateIconIndirect(&iconInfo1); // リソース解放 SelectObject(hdc_mem, hBmpOld); DeleteObject(iconInfo1.hbmColor); DeleteDC(hdc_mem); こんな感じでしょうかね。「BITMAPINFOの準備」で作ったpbiをGetDIBits()やSetDIBits()のBITMAPINFO *引数の箇所に与えれば、動きます。 やはり、AIが単独でプログラミングするのはまだ難しいですが、一方で僕一人で上記の手順にたどり着くこともまた難しかったと思います。なので、AIの出力物に対し、適切なレビューまたは手直しを行う人間がいれば、かなり期間短縮が果たせるということは、実証できたのかなといったところです。 ちなみに現在公開しているβ版は、技術検証しながらの作成だったこともあり、hdcやhdc_memはアイコン合成をやるたびに作ったり消したりを繰り返す状態になってます。48回もこれを繰り返すのは無駄でしかないので、正式版公開にあたっては、その辺りの流れを効率よくしておきたいと思います。 目次の表示: ブログではないので、コメント機能とトラックバック機能は提供していません。ご質問・ご意見等はメール、フィードバックまたはTwitter等からお願いします。いただいたご質問・ご意見などは、この「管理人のひとこと」の記事に追加、あるいは新規の記事にする形で一部または全文をそのまま、あるいは加工させていただいた上で、ご紹介させていただく場合があります。 当サイトでは掲載内容による不具合等に関する責任を持ちません。また、内容の正確性についての保証もありませんので、情報をご利用の際は、利用者の自己責任で確認をお願いします。 |
- 最近の更新 - |
|
3285250 (+0036)[+0928] Copyright© 2010-2025 INASOFT |