|
![]() | |
|
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等からお願いします。いただいたご質問・ご意見などは、この「管理人のひとこと」の記事に追加、あるいは新規の記事にする形で一部または全文をそのまま、あるいは加工させていただいた上で、ご紹介させていただく場合があります。 当サイトでは掲載内容による不具合等に関する責任を持ちません。また、内容の正確性についての保証もありませんので、情報をご利用の際は、利用者の自己責任で確認をお願いします。 |
- 最近の更新 - |
|
|
3401597 (+0129)[+1020] Copyright© 2010-2025 INASOFT | ||