質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

4597閲覧

WinAPI AlphaBlendのDIB定義

Weapon

総合スコア106

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/09/14 16:50

前提・実現したいこと

前回の質問から改めてAlphaBlendのレイヤードウィンドウのレンダリングについて質問です。
親ウィンドウはレイヤードウィンドウでWS_EX_RAYEREDを使い
子ウィンドウはWS_ES_TRANSPARENTでウィンドウを作りました。
今回子ウィンドウに透過DIBをAlphaBlendしようと思ったのですがうまくレンダリングされません。
うまく配列代入ができていないのでしょうか。

該当のソースコード

C

1#define UNICODE 2 3#include <Windows.h> 4 5#pragma comment(lib,"msimg32.lib") 6 7LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 8LRESULT CALLBACK ChildWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 9 10HINSTANCE hInst; 11 12const wchar_t CLASS_NAME[] = L"Layered Window"; 13const wchar_t CHILD_CLASS_NAME[] = L"Transparent Window"; 14 15int imgWidth = 300; 16int imgHeight = 500; 17 18int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) 19{ 20 hInst = hInstance; 21 22 WNDCLASSEX wc = { 23 sizeof(WNDCLASSEX),CS_VREDRAW | CS_HREDRAW,WindowProc,0, 24 0,hInstance,NULL,LoadCursor(NULL, IDC_ARROW), 25 (HBRUSH)WHITE_BRUSH,NULL,CLASS_NAME,NULL 26 }; 27 28 RegisterClassEx(&wc); 29 30 HWND hwnd = CreateWindowEx( 31 WS_EX_LAYERED, CLASS_NAME, CLASS_NAME, WS_OVERLAPPEDWINDOW, 32 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, NULL, hInstance, NULL 34 ); 35 if (hwnd == NULL)return 0; 36 37 ShowWindow(hwnd, nCmdShow); 38 39 MSG msg = {}; 40 41 while (GetMessage(&msg, NULL, 0, 0)) 42 { 43 TranslateMessage(&msg); 44 DispatchMessage(&msg); 45 } 46 47 return 0; 48} 49 50LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 51{ 52 COLORREF cr = RGB(255, 0, 0); 53 switch (uMsg) { 54 case WM_CREATE: 55 { 56 SetLayeredWindowAttributes(hwnd, cr, 0x0, LWA_COLORKEY); 57 58 WNDCLASSEX wc = { 59 sizeof(WNDCLASSEX),CS_VREDRAW | CS_HREDRAW,ChildWindowProc,0, 60 0,hInst,NULL,LoadCursor(NULL, IDC_ARROW), 61 (HBRUSH)WHITE_BRUSH,NULL,CHILD_CLASS_NAME,NULL 62 }; 63 64 RegisterClassEx(&wc); 65 66 HWND chwnd = CreateWindowEx( 67 WS_EX_TRANSPARENT, CHILD_CLASS_NAME, NULL, WS_VISIBLE | WS_THICKFRAME | WS_CHILD, 68 50, 50, 300, 500, 69 hwnd, NULL, hInst, NULL 70 ); 71 72 if (chwnd == NULL)return 0; 73 74 ShowWindow(chwnd, SW_SHOW); 75 } 76 break; 77 78 case WM_DESTROY: 79 PostQuitMessage(0); 80 return 0; 81 82 case WM_PAINT: 83 { 84 PAINTSTRUCT ps; 85 HDC hdc = BeginPaint(hwnd, &ps); 86 HBRUSH hBrush = CreateSolidBrush(cr); 87 88 FillRect(hdc, &ps.rcPaint, hBrush); 89 90 EndPaint(hwnd, &ps); 91 DeleteObject(hBrush); 92 93 SetLayeredWindowAttributes(hwnd, cr, 0x0, LWA_COLORKEY); 94 } 95 break; 96 97 } 98 99 return DefWindowProc(hwnd, uMsg, wParam, lParam); 100} 101 102LRESULT CALLBACK ChildWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 103 switch (uMsg) { 104 case WM_PAINT: 105 { 106 HDC hdc; //for window 107 HDC himgdc; //for image 108 BLENDFUNCTION bf; 109 BITMAPINFO bmpi; 110 HBITMAP hbitmap; 111 int winWidth, winHeight; 112 RECT rClient; 113 114 hdc = GetDC(hwnd); 115 GetClientRect(hwnd, &rClient); 116 117 winWidth = rClient.right - rClient.left; 118 winHeight = rClient.bottom - rClient.top; 119 120 himgdc = CreateCompatibleDC(hdc); 121 122//子ウィンドウDIB定義 123 DWORD **image = (DWORD**)malloc(sizeof(DWORD*)*imgWidth); 124 DWORD *image_c = (DWORD*)malloc(sizeof(DWORD)*imgWidth*imgHeight); 125 for (int i = 0; i < imgWidth; i++)image[i] = image_c + i * imgHeight; 126 for (int i = 0; i < imgWidth; i++)for (int j = 0; j < imgHeight; j++)image[i][j] = 0xff000000; 127 128 DWORD** dib = (DWORD**)calloc(imgWidth*imgHeight, sizeof(DWORD*)); 129 130 for (int i = 0; i < imgWidth; i++)for (int j = 0; j < imgHeight; j++)dib[j+i*imgWidth] = &image[j][i]; 131 //image配列のxy座標系をDIBのxy座標系に変換するもの 132 133 134 ZeroMemory(&bmpi, sizeof(BITMAPINFO)); 135 136 bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 137 bmpi.bmiHeader.biWidth = imgWidth; 138 bmpi.bmiHeader.biHeight = imgHeight; 139 bmpi.bmiHeader.biPlanes = 1; 140 bmpi.bmiHeader.biBitCount = 32; 141 bmpi.bmiHeader.biCompression = BI_RGB; 142 143//おそらく間違っている場所 144 hbitmap = CreateDIBSection(himgdc, &bmpi, DIB_RGB_COLORS, (void**)&dib, NULL, 0x0); 145 if(hbitmap==NULL)MessageBox(hwnd, L"Failed to male CreateDIBSection", L"CAUTION", IDOK); 146 147 SelectObject(himgdc, hbitmap); 148 149 bf.BlendOp = AC_SRC_OVER; 150 bf.BlendFlags = 0; 151 bf.SourceConstantAlpha = 0xff; 152 bf.AlphaFormat = AC_SRC_ALPHA; 153 154 if (!AlphaBlend(hdc, 0, 0, 300, 500, himgdc, 0, 0, imgWidth, imgHeight, bf))return 0; 155 156 DeleteObject(hbitmap); 157 DeleteDC(himgdc); 158 DeleteDC(hdc); 159 160 free(image_c); 161 free(image); 162 } 163 break; 164 } 165 return DefWindowProc(hwnd, uMsg, wParam, lParam); 166}

補足情報(FW/ツールのバージョンなど)

Windows10 Pro
VisualStudio 2017 Community

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

この質問は回答者の観点からすると、かなり回答しにくい内容になっているかと思います。それは以下の点のそれぞれの相互作用について理解していないと最終的な回答とするのが難しいためです。
1.レイヤードウィンドウと透過子ウィンドウの関係
2.透過子ウィンドウに対する AlphaBlend の効果
3.CreateDIBSection の使い方
4.AlphaBlend に渡す DIB セクションの内容
このうち、3と4の AlphaBlend に渡すことが可能な CreateDIBSection の使い方について回答します。それ以外の点については AlphaBlend と CreateDIBSection について解決できた時点で問題があれば、別に質問していただけると他の回答者からも回答が付きやすいかと思います。

提示されているソースの問題点は CreateDIBSection の使い方にあります。CreateDIBSection の 5 番目の hSection パラメータに NULL を指定する場合、4 番目のパラメータで指定するのは OS が割り当てた DIB セクション用メモリブロックを受け取るポインタを指定する必要があります。ですので、ここに malloc や calloc で割り当てたメモリを指定することはできません。こちらで事前に用意したメモリブロック(バイト配列)をビットマップオブジェクトに転送するには SetDIBits を使用します。また、この使用方法をとる場合、 bmpi.bmiHeader.biSizeImage には割り当てるメモリブロックのサイズを計算して設定する必要があります。

提示されているコードに誤りはありませんが、アルファブレンドのアルファチャネルは以下の構造体と同じ構成になっている必要があります。
https://docs.microsoft.com/ja-jp/windows/desktop/gdi/alpha-blending

また、CreateDIBSection と AlphaBlend の複合サンプルは以下のページになります。
https://docs.microsoft.com/ja-jp/windows/desktop/gdi/alpha-blending-a-bitmap

最後に、Github に CreateDIBSection と AlphaBlend のサンプルを上げました。
https://github.com/atata0319/teratail146688
このサンプルは CreateDIBSection で作られたメモリ領域のアルファチャネルに相当する部分だけを書き換えることによりアルファブレンド効果を得ていることを確認するためのものです。このプロジェクトをビルドいただくと以下のような合成を実施することができます。
AlphaBlend結果
残念ながらアルファブレンド効果の薄い画像を使用してしまったので、きれいに合成されていないように見えます。

投稿2018/09/15 19:55

atata0319

総合スコア881

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Weapon

2018/09/17 15:48

コード拝見させていただきました。丁寧にありがとうございます。 i)確認ですがAlphaBlendは画像をほかの画像のDCハンドルを指定するものであってウィンドウのDCハンドルを指定はできないということですか? そして細かく分けていただいた 1.レイヤードウィンドウと透過子ウィンドウの関係 2.透過子ウィンドウに対する AlphaBlend の効果 はまた別に質問させていただきますが ii)透過bmpはそもそもウィンドウの下地を画像の透過部位から見せることは不可能なのでしょうか iii)SetDIBitsは透過DIBをサポートしていないと見たのですがii)と同様できない仕様で指定色での塗りつぶし以外の方法はないのでしょうか
atata0319

2018/09/17 16:44

i) AlphaBlend の転送先の hdc は BeginPaint して得たウィンドウのDCハンドルです。AlphaBlend の前に転送先画像として白い画像を転送しているため確認しづらいかもしれませんが。 転送元は CreateDIBSection で作成した DIB でなけれなばなりません。32 ビットのアルファチャネル付ビットマップを標準の Win32 API (LoadBitmap等)はサポートしていないためです。 ※Windows 10 でサポートされるようになったかは調べていません。 ii) i)が可能ですので可能です。Github のサンプルを更新しておきました。10ピクセル毎に透過転送と非透過転送を切り替えています。 iii) これはその通りです。SetDIBits は透過 DIB をサポートしていません。この関数は質問のコードのようにプログラム側で確保したメモリ領域を転送する関数の例ということで挙げています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問