-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGetColorTableFromBitmap.cpp
More file actions
118 lines (98 loc) · 3.81 KB
/
Copy pathGetColorTableFromBitmap.cpp
File metadata and controls
118 lines (98 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <windows.h>
#include <vector>
#include <stdexcept>
/// DIBビットマップのHBITMAPからカラーテーブルを取得する
/// @param hBitmap 対象のHBITMAP(DIBセクションであること)
/// @param colors 取得したRGBQUADのリストを受け取るvector
/// @return カラーテーブルのエントリ数(0ならカラーテーブルなし)
int GetDIBColorTable(HBITMAP hBitmap, std::vector<RGBQUAD>& colors)
{
colors.clear();
if (!hBitmap)
throw std::invalid_argument("hBitmap is NULL");
// --- 1. BITMAPINFOの取得 -------------------------------------------
// GetDIBits を2段階呼び出し:1回目でヘッダサイズ確認、2回目で実データ取得
BITMAPINFOHEADER bih = {};
bih.biSize = sizeof(BITMAPINFOHEADER);
HDC hdc = ::GetDC(NULL);
if (!hdc)
throw std::runtime_error("GetDC failed");
// 1回目: ピクセルデータなしで BITMAPINFOHEADER だけ埋めてもらう
if (!::GetDIBits(hdc, hBitmap, 0, 0, NULL,
reinterpret_cast<BITMAPINFO*>(&bih), DIB_RGB_COLORS))
{
::ReleaseDC(NULL, hdc);
throw std::runtime_error("GetDIBits(header) failed");
}
// --- 2. カラーテーブルのエントリ数を算出 ----------------------------
WORD bitCount = bih.biBitCount;
DWORD clrUsed = bih.biClrUsed;
DWORD numColors;
if (bitCount == 1 || bitCount == 4 || bitCount == 8)
{
// パレット形式: clrUsed==0 のときは最大エントリ数
numColors = (clrUsed > 0) ? clrUsed : (1u << bitCount);
}
else if (bitCount == 16 || bitCount == 32)
{
// BI_BITFIELDS の場合はマスク用に3エントリ持つことがある
numColors = (clrUsed > 0) ? clrUsed : 0;
}
else // 24bpp など
{
numColors = (clrUsed > 0) ? clrUsed : 0;
}
if (numColors == 0)
{
::ReleaseDC(NULL, hdc);
return 0; // カラーテーブルなし
}
// --- 3. BITMAPINFO + カラーテーブル分のバッファを確保 ---------------
// BITMAPINFO の末尾 bmiColors[1] の1エントリ分はすでに含まれているので
// (numColors - 1) エントリ分だけ追加確保する
size_t bufSize = sizeof(BITMAPINFOHEADER)
+ sizeof(RGBQUAD) * numColors;
std::vector<BYTE> buf(bufSize, 0);
BITMAPINFO* pBmi = reinterpret_cast<BITMAPINFO*>(&buf[0]);
pBmi->bmiHeader = bih;
// 2回目: カラーテーブルも含めて取得
if (!::GetDIBits(hdc, hBitmap, 0, 0, NULL, pBmi, DIB_RGB_COLORS))
{
::ReleaseDC(NULL, hdc);
throw std::runtime_error("GetDIBits(color table) failed");
}
::ReleaseDC(NULL, hdc);
// --- 4. RGBQUAD 配列を vector に詰める ------------------------------
const RGBQUAD* pTable = pBmi->bmiColors;
colors.assign(pTable, pTable + numColors);
return static_cast<int>(numColors);
}
#ifdef DEMO
#include <stdio.h>
int main()
{
// 8bpp DIBセクションを作成(テスト用)
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 64;
bmi.bmiHeader.biHeight = 64;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 8;
bmi.bmiHeader.biCompression = BI_RGB;
void* pBits = NULL;
HBITMAP hBmp = ::CreateDIBSection(NULL, &bmi,
DIB_RGB_COLORS, &pBits, NULL, 0);
// カラーテーブルを取得
std::vector<RGBQUAD> palette;
int n = GetDIBColorTable(hBmp, palette);
printf("entries: %d\n", n);
for (int i = 0; i < n; ++i)
{
printf("[%3d] R=%3d G=%3d B=%3d\n",
i, palette[i].rgbRed,
palette[i].rgbGreen,
palette[i].rgbBlue);
}
::DeleteObject(hBmp);
}
#endif