我想使用
BitBlt
将颜色值缓冲区移动到窗口,只有窗口显示为空。当我编译并运行如何在窗口中加载位图?(使用我自己的示例 .bmp 文件)中的代码时,窗口也显示为空。
经过一些测试,问题似乎出在
SelectObject()
。根据文档,当返回值为 NULL 时,会发生错误:https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-selectobject。返回值为NULL,但GetLastError()
给出0,表示没有错误。这里有什么问题吗?
case WM_CREATE:
std::fill(arr, arr + sizeof(arr), RGB(255,0,0));
hBitmap = CreateBitmap(240, 120, 1, sizeof(COLORREF), (void*) arr);
UpdateWindow(hwnd);
break;
case WM_PAINT:
PAINTSTRUCT ps;
BITMAP bitmap;
HGDIOBJ oldBitmap;
HDC hdcMem;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
hdcMem = CreateCompatibleDC(hdc);
oldBitmap = SelectObject(hdcMem, hBitmap);
std::cout << (oldBitmap == NULL) << std::endl;
std::cout << GetLastError();
GetObject(hBitmap, sizeof(bitmap), &bitmap);
BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
break;
(顺便说一句:每次我需要
main()
时,我都会使用 WinMain()
代替 GetModuleHandle(NULL)
和 hInstance
。由于窗口功能正常,我怀疑它与此无关,但无论如何我都会提到它。)
---解决了!---
我现在已经可以使用了:)对于看到这个的其他人来说,这就是我所做的更改:
case WM_CREATE:
std::fill(arr, arr + 240 * 120, RGB(255,0,0));
hBitmap = CreateBitmap(240, 120, 1, sizeof(COLORREF) * 8, (void*) arr);
UpdateWindow(hwnd);
break;
如果
arr
是指针,则使用元素总数 (240 * 120
)
如果
arr
是一个数组,sizeof
将返回总大小(以字节为单位)。而是使用 sizeof(arr)/sizeof(*arr)
来查找数组的计数(数组元素的总数,或像素的总数)。例如,假设 arr
的元素是 32 位,那么您正在查看 240 * 120
像素,其中每个像素是 4 个字节或 32 位。
CreateBitmap
的第四个参数期望大小以位为单位,因此它应该是 sizeof(*arr) * 8
或只是 32。
uint32_t arr[240 * 120];
std::fill(arr, arr + sizeof(arr)/sizeof(*arr), RGB(255, 0, 0));
//or std::fill(arr, arr + 240 * 120, RGB(255, 0, 0));
hBitmap = CreateBitmap(240, 120, 1, 32, (void*)arr);
请注意,这将生成蓝色位图,而不是红色,因为它使用 BGR 格式而不是 RGB。
看来你已经知道如何使用内存dc了。您可以使用
CreateCompatibleBitmap
创建位图,然后将该位图选择到内存 dc 中,并使用标准 GDI 函数,例如 FillRect
。这将避免计算位和字节的陷阱。
C++ 类波纹管允许使用
CreateBitmap
函数轻松创建位图。
ColorU
像素阵列。CreateBitmap
函数创建位图。在示例中,为了简单起见,省略了错误检查。
// pixel array dimensions
const int32_t width = 720, height = 480;
Graphics::ColorU *pixelArray = new ColorU[width * height];
for (size_t i = 0; i < width * height; i++) {
pixelArray[i].setColor(Graphics::ColorU::DarkBlue);
}
// assume "window" is valid window handle
RECT client = GetWindowRect(window, &rect);
// assume "windowDC" is valid window DC
HDC tempDC = CreateCompatibleDC(windowDC);
HBITMAP bitmap = CreateBitmap(width, height, 1, 32, pixelArray);
HGDIOBJ obj = SelectObject(tempDC, bitmap);
BitBlt(windowDC, 0, 0,
client.right - client.left,
client.bottom - client.top,
tempDC, 0, 0, SRCCOPY);
SelectObject(tempDC, obj);
DeleteDC(tempDC);
DeleteObject(bitmap);
delete[] pixelArray;
#ifndef _COLOR_U_H_
#define _COLOR_U_H_
#include <stdint.h>
using Byte = uint8_t;
using Word = uint16_t;
using Dword = uint32_t;
using Float = float;
using Uint32 = uint32_t;
using ColorRef = Dword;
#pragma pack(push, 1)
#pragma warning(disable:4005)
#define RGB(r, g, b) (ColorRef)(((Byte)(r))|(((Word)((Byte)(g)))<<8)|(((Dword)((Byte)(b)))<<16))
#define GetRValue(rgb) (Byte)((Dword)(rgb))
#define GetGValue(rgb) (Byte)(((Word)((Dword)(rgb)))>>8)
#define GetBValue(rgb) (Byte)(((Dword)(rgb))>>16)
#pragma warning(default:4005)
namespace Graphics {
// ----------------------------------------------------------------
// Class "ColorU"
// - This Class Provides GDI Compatible Color Manipulations
// Color Format
// - BBGGRRXX: [ Blue:Byte, Green:Byte, Red:Byte, Reserved:Byte ]
// ----------------------------------------------------------------
class ColorU {
public:
enum KnownColor : ColorRef {
White = RGB(191, 191, 191),
Gray = RGB(89, 89, 89),
BrightWhite = RGB(255, 255, 255),
Black = RGB(0, 0, 0),
Red = RGB(255, 0, 0),
Green = RGB(0, 255, 0),
Blue = RGB(0, 0, 255),
LightRed = RGB(255, 128, 128),
LightGreen = RGB(128, 255, 128),
LightBlue = RGB(128, 128, 255),
DarkRed = RGB(128, 0, 0),
DarkGreen = RGB(0, 128, 0),
DarkBlue = RGB(0, 0, 128),
Aqua = RGB(0, 191, 255),
Purple = RGB(191, 0, 255),
Yellow = RGB(255, 191, 0),
LightAqua = RGB(0, 255, 255),
LightPurple = RGB(255, 0, 255),
LightYellow = RGB(255, 255, 0)
};
enum class Property : Byte {
Blue, Green, Red
};
// ----------------------------------------
// constructors
ColorU() noexcept {
m_blue = 0x00;
m_green = 0x00;
m_red = 0x00;
m_reserved = 0x00;
}
ColorU(KnownColor knownColor) noexcept {
m_blue = GetBValue(knownColor);
m_green = GetGValue(knownColor);
m_red = GetRValue(knownColor);
m_reserved = 0x00;
}
explicit ColorU(Byte red, Byte green, Byte blue) noexcept {
m_blue = blue;
m_green = green;
m_red = red;
m_reserved = 0x00;
}
ColorU(ColorRef rgbColor) noexcept {
m_blue = GetBValue(rgbColor);
m_green = GetGValue(rgbColor);
m_red = GetRValue(rgbColor);
m_reserved = 0x00;
}
// input color component range: [0, 1]
explicit ColorU(Float red, Float green, Float blue) noexcept {
m_blue = blue <= 0.0F ? 0 : blue >= 1.0F ? 255 : (Byte)(blue * 255);
m_green = green <= 0.0F ? 0 : green >= 1.0F ? 255 : (Byte)(green * 255);
m_red = red <= 0.0F ? 0 : red >= 1.0F ? 255 : (Byte)(red * 255);
m_reserved = 0x00;
}
// ----------------------------------------
// copy constructor
ColorU(const ColorU &other) noexcept = default;
// copy assigment operator
ColorU& operator=(const ColorU &other) noexcept = default;
// ----------------------------------------
// getters / setters
void setColor(KnownColor knownColor) noexcept {
m_blue = GetBValue(knownColor);
m_green = GetGValue(knownColor);
m_red = GetRValue(knownColor);
}
void setColor(Byte red, Byte green, Byte blue) noexcept {
m_blue = blue;
m_green = green;
m_red = red;
}
void setColor(ColorRef rgbColor) noexcept {
m_blue = GetBValue(rgbColor);
m_green = GetGValue(rgbColor);
m_red = GetRValue(rgbColor);
}
// input color component range: [0, 1]
void setColor(Float red, Float green, Float blue) noexcept {
m_blue = blue <= 0.0F ? 0 : blue >= 1.0F ? 255 : (Byte)(blue * 255);
m_green = green <= 0.0F ? 0 : green >= 1.0F ? 255 : (Byte)(green * 255);
m_red = red <= 0.0F ? 0 : red >= 1.0F ? 255 : (Byte)(red * 255);
}
// ----------------------------------------
Byte getProperty(Property property) const noexcept {
switch (property) {
case Property::Blue:
return m_blue;
case Property::Green:
return m_green;
case Property::Red:
return m_red;
default:
return 0U;
}
}
void setProperty(Property property, Byte value) noexcept {
switch (property) {
case Property::Blue:
m_blue = value;
break;
case Property::Green:
m_green = value;
break;
case Property::Red:
m_red = value;
break;
}
}
// ----------------------------------------
// hashing
Uint32 hash() const noexcept {
Uint32 hash = 47837;
const Byte *data = (const Byte *)(this);
Byte slidingWindow = 0x00;
for (Byte i = 0; i < sizeof(ColorU) - 1; i++) {
slidingWindow <<= 4;
slidingWindow |= (data[i] & 0xF0) >> 4;
hash += slidingWindow * (i + 1);
slidingWindow <<= 4;
slidingWindow |= (data[i] & 0x0F);
hash += slidingWindow * (i + 1);
}
hash |= (hash ^ 47837) << 16;
return hash;
}
// ----------------------------------------
bool equal(const ColorU &other) const noexcept {
return (
m_blue == other.m_blue &&
m_green == other.m_green &&
m_red == other.m_red
);
}
bool operator==(const ColorU &other) const noexcept {
return equal(other);
}
bool operator!=(const ColorU &other) const noexcept {
return !equal(other);
}
// ----------------------------------------
// conversion
ColorRef data() const noexcept {
return RGB(m_red, m_green, m_blue);
}
operator ColorRef() const noexcept {
return RGB(m_red, m_green, m_blue);
}
// ----------------------------------------
// default destructor
~ColorU() noexcept = default;
private:
Byte m_blue;
Byte m_green;
Byte m_red;
Byte m_reserved;
};
}
#pragma pack(pop)
#endif // !_COLOR_U_H_