|
![]() ![]() ![]() ![]() ![]() | |
Windows APIを利用したアイコンのOR合成の方法について、先日は「Windowsに詳しそう」という理由だけでCopilotに答えを求めて失敗してしまいましたが、別の生成AIだとどんな回答がもらえるか、試してみないとAIの名誉のためによろしくないかな?ということで、別の生成AIにも聞いてい見ることにしました。 というわけで、ChatGPTに聞いてみることにしました。 2つのLoadImage APIで取得したアイコンハンドルをOR演算で重ね合わせて1つのアイコンに合成し、そのアイコンハンドルを取得する方法を教えてください。 手順の概要
#include <windows.h> HICON CombineIcons(HICON hIcon1, HICON hIcon2) { ICONINFO iconInfo1, iconInfo2; GetIconInfo(hIcon1, &iconInfo1); GetIconInfo(hIcon2, &iconInfo2); BITMAP bmp1, bmp2; GetObject(iconInfo1.hbmColor, sizeof(BITMAP), &bmp1); GetObject(iconInfo2.hbmColor, sizeof(BITMAP), &bmp2); int width = bmp1.bmWidth; int height = bmp1.bmHeight; // 対応するBITMAPINFO作成 BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = -height; // top-down DIB bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; // RGBA bmi.bmiHeader.biCompression = BI_RGB; HDC hdc = GetDC(NULL); DWORD* pixels1 = new DWORD[width * height]; DWORD* pixels2 = new DWORD[width * height]; DWORD* combinedPixels = new DWORD[width * height]; GetDIBits(hdc, iconInfo1.hbmColor, 0, height, pixels1, &bmi, DIB_RGB_COLORS); GetDIBits(hdc, iconInfo2.hbmColor, 0, height, pixels2, &bmi, DIB_RGB_COLORS); for (int i = 0; i < width * height; ++i) { combinedPixels[i] = pixels1[i] | pixels2[i]; // ピクセルごとに OR 合成 } HBITMAP hbmColor = CreateCompatibleBitmap(hdc, width, height); SetDIBits(hdc, hbmColor, 0, height, combinedPixels, &bmi, DIB_RGB_COLORS); // マスクビットマップは片方のものを使う(必要に応じて OR 処理) HICON hCombinedIcon; ICONINFO ii = {}; ii.fIcon = TRUE; ii.hbmColor = hbmColor; ii.hbmMask = iconInfo1.hbmMask; hCombinedIcon = CreateIconIndirect(&ii); // 後始末 delete[] pixels1; delete[] pixels2; delete[] combinedPixels; DeleteObject(iconInfo1.hbmColor); DeleteObject(iconInfo2.hbmColor); DeleteObject(iconInfo1.hbmMask); DeleteObject(iconInfo2.hbmMask); ReleaseDC(NULL, hdc); return hCombinedIcon; }補足 このコードは32ビットのカラーアイコンに対応しています。 OR 演算を他の(AND, XORなど)に変えることで、別の合成効果も作れます。 マスクビットマップも合成したい場合は、同様の方法でORしてください。 なんか大丈夫そうです。でも、アイコンは16色モードで使いたいので、16色モード用のプログラムにしてもらませんかね。 16色(4ビット)モードのアイコンを作成するには、ビットマップの カラービット数を4ビット(biBitCount = 4) に設定し、カラーパレット(RGBQUAD)を含むDIB を用いる必要があります。
#include <windows.h> #include <vector> HICON Combine16ColorIcons(HICON hIcon1, HICON hIcon2) { ICONINFO ii1, ii2; GetIconInfo(hIcon1, &ii1); GetIconInfo(hIcon2, &ii2); BITMAP bmp; GetObject(ii1.hbmColor, sizeof(BITMAP), &bmp); int width = bmp.bmWidth; int height = bmp.bmHeight; BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = height; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 4; // 4bpp (16色) bmi.bmiHeader.biCompression = BI_RGB; const int imageSize = ((width + 1) / 2) * height; // 4bpp = 2ピクセル/バイト std::vector注意点 SetDIBits に与える BITMAPINFO には RGBQUAD パレットを含む必要がありますが、標準パレットを使うため省略可です(必要なら BITMAPINFO を拡張)。 もし元アイコンが24bitや32bitカラーの場合、4bitに減色処理を事前に行う必要があります。 16色アイコンの透明度は ANDマスク(白=透明, 黒=不透明)で表現されます。 RGBQUAD palette[16]を定義しているけど、どこにも使われていないじゃん……という不思議さがありますが、「SetDIBits に与える BITMAPINFO には RGBQUAD パレットを含む必要がありますが、標準パレットを使うため省略可です(必要なら BITMAPINFO を拡張)」って、知らなかった……!省略可能だったのか! ちなみに、GoogleのGeminiにも聞いてみたのですが、生成されたコードはエラー処理を含む極めて巨大なもので、記事としてネタとして成立しづらいものだったので省略します。16色にしてほしいとお願いしたけど16色になっていなかったり(※)、最終結果の出力先を画面にしていたのですが、その様子があまりにもおかしいコードが出力されていました。 目次の表示: ブログではないので、コメント機能とトラックバック機能は提供していません。ご質問・ご意見等はメール、フィードバックまたはTwitter等からお願いします。いただいたご質問・ご意見などは、この「管理人のひとこと」の記事に追加、あるいは新規の記事にする形で一部または全文をそのまま、あるいは加工させていただいた上で、ご紹介させていただく場合があります。 当サイトでは掲載内容による不具合等に関する責任を持ちません。また、内容の正確性についての保証もありませんので、情報をご利用の際は、利用者の自己責任で確認をお願いします。 |
- 最近の更新 - |
|
3286475 (+0075)[+0504] Copyright© 2010-2025 INASOFT |