如何使用 Direct2D 从 BITMAPINFOHEADER 和 BYTE 渲染位图
How to Render a Bitmap from BITMAPINFOHEADER and BYTE using Direct2D
我正在尝试创建一个 C++ 应用程序,它实际上从放大镜捕获位图并使用 Direct 2d 渲染它。
我目前正在编写将位图从放大镜保存到文件的代码。但我需要做的是使用直接 2d 将该位图绘制到我的 window 而不是将其保存到文件中。
放大镜 returns 图像作为 MAGIMAGEHEADER 形式的结构,我能够从中获得 BITMAPINFOHEADER 和字节。我需要使用直接 2D 将其渲染为 window。
这是用于从 Magnifier API
获取 BITMAPINFOHEADER 和字节的代码
BOOL MagImageScaling(HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata, MAGIMAGEHEADER destheader,RECT unclipped, RECT clipped, HRGN dirty)
{
// Setup the bitmap info header
bmif.biSize = sizeof(BITMAPINFOHEADER);
bmif.biHeight = srcheader.height;
bmif.biWidth = srcheader.width;
bmif.biSizeImage = srcheader.cbSize;
bmif.biPlanes = 1;
bmif.biBitCount = (WORD)(bmif.biSizeImage / bmif.biHeight / bmif.biWidth * 8);
bmif.biCompression = BI_RGB;
// Prepare the buffer
if (pData != NULL)
{
delete pData;
pData = NULL;
}
pData = (BYTE*)malloc(bmif.biSizeImage);
memcpy(pData, srcdata, bmif.biSizeImage);
// The data bit is in top->bottom order, so we convert it to bottom->top order
LONG lineSize = bmif.biWidth * bmif.biBitCount / 8;
BYTE* pLineData = new BYTE[lineSize];
BYTE* pStart;
BYTE* pEnd;
LONG lineStart = 0;
LONG lineEnd = bmif.biHeight - 1;
while (lineStart < lineEnd)
{
// Get the address of the swap line
pStart = pData + (lineStart * lineSize);
pEnd = pData + (lineEnd * lineSize);
// Swap the top with the bottom
memcpy(pLineData, pStart, lineSize);
memcpy(pStart, pEnd, lineSize);
memcpy(pEnd, pLineData, lineSize);
// Adjust the line index
lineStart++;
lineEnd--;
}
delete pLineData;
// Set the flag to say that the callback function is finished
bCallbacked = TRUE;
return TRUE;
}
这里变量bmif是BITMAPINFOHEADER,pData是Bytes
有什么办法可以实现吗?
如果你有HBITMAP
句柄,你可以这样做:
您的图片大小使用:::GetObject(hBmp, sizeof(BITMAP), &bmpSizeInfo);
像这样填写BITMAPINFO
:
memset(&bmpData, 0, sizeof(BITMAPINFO));
bmpData.bmiHeader.biSize = sizeof(bmpData.bmiHeader);
bmpData.bmiHeader.biHeight = -bmpSizeInfo.bmHeight;
bmpData.bmiHeader.biWidth = bmpSizeInfo.bmWidth;
bmpData.bmiHeader.biPlanes = bmpSizeInfo.bmPlanes;
bmpData.bmiHeader.biBitCount = bmpSizeInfo.bmBitsPixel;
创建足够的堆内存来保存位图数据:
pBuff = new char[bmpSizeInfo.bmWidth * bmpSizeInfo.bmHeight * 4];
像这样获取位图数据:
::GetDIBits(hDc, hBmp, 0, bmpSizeInfo.bmHeight, (void*)pBuff, &bmpData, DIB_RGB_COLORS);
创建一个 D2D1_BITMAP_PROPERTIES
并像这样填充它:
bmpPorp.dpiX = 0.0f;
bmpPorp.dpiY = 0.0f;
bmpPorp.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bmpPorp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
使用您的渲染目标将数据转换为 ID2D1Bitmap
pRT->CreateBitmap(bmpSize, pBuff, 4 * bmpSizeInfo.bmWidth, bmpPorp, &pBmpFromH);
这里是如何在 Direct2D 中使用 mag 的位图。您不需要 BITMAPINFOHEADER 因为 mag 格式与 DXGI_FORMAT_B8G8R8A8_UNORM:
相同
BOOL MagImageScaling(HWND hwnd, void* srcdata, MAGIMAGEHEADER srcheader, void* destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty)
{
// note: all this (dc, surface, targte) can be created only once as long as the D3D device isn't reset
ComPtr<ID2D1DeviceContext> dc;
HR(d2Device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, dc.GetAddressOf()));
ComPtr<IDXGISurface2> surface;
HR(swapChain->GetBuffer(0, IID_PPV_ARGS(&surface)));
ComPtr<ID2D1Bitmap1> target;
HR(dc->CreateBitmapFromDxgiSurface(surface.Get(), NULL, target.GetAddressOf()));
dc->SetTarget(target.Get());
D2D1_BITMAP_PROPERTIES properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
// note: this is ok as srcheader.format (GUID_WICPixelFormat32bppRGBA) is compatible
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
D2D1_SIZE_U size = {};
size.width = srcheader.width;
size.height = srcheader.height;
ComPtr<ID2D1Bitmap> bitmap;
HR(dc->CreateBitmap(size, properties, bitmap.GetAddressOf()));
HR(bitmap->CopyFromMemory(NULL, srcdata, srcheader.stride));
dc->BeginDraw();
// note: we don't call this because we draw on the whole render target
//dc->Clear();
dc->DrawBitmap(bitmap.Get());
HR(dc->EndDraw());
HR(swapChain->Present(1, 0));
return TRUE;
}
我正在尝试创建一个 C++ 应用程序,它实际上从放大镜捕获位图并使用 Direct 2d 渲染它。
我目前正在编写将位图从放大镜保存到文件的代码。但我需要做的是使用直接 2d 将该位图绘制到我的 window 而不是将其保存到文件中。
放大镜 returns 图像作为 MAGIMAGEHEADER 形式的结构,我能够从中获得 BITMAPINFOHEADER 和字节。我需要使用直接 2D 将其渲染为 window。
这是用于从 Magnifier API
获取 BITMAPINFOHEADER 和字节的代码BOOL MagImageScaling(HWND hwnd, void *srcdata, MAGIMAGEHEADER srcheader, void *destdata, MAGIMAGEHEADER destheader,RECT unclipped, RECT clipped, HRGN dirty)
{
// Setup the bitmap info header
bmif.biSize = sizeof(BITMAPINFOHEADER);
bmif.biHeight = srcheader.height;
bmif.biWidth = srcheader.width;
bmif.biSizeImage = srcheader.cbSize;
bmif.biPlanes = 1;
bmif.biBitCount = (WORD)(bmif.biSizeImage / bmif.biHeight / bmif.biWidth * 8);
bmif.biCompression = BI_RGB;
// Prepare the buffer
if (pData != NULL)
{
delete pData;
pData = NULL;
}
pData = (BYTE*)malloc(bmif.biSizeImage);
memcpy(pData, srcdata, bmif.biSizeImage);
// The data bit is in top->bottom order, so we convert it to bottom->top order
LONG lineSize = bmif.biWidth * bmif.biBitCount / 8;
BYTE* pLineData = new BYTE[lineSize];
BYTE* pStart;
BYTE* pEnd;
LONG lineStart = 0;
LONG lineEnd = bmif.biHeight - 1;
while (lineStart < lineEnd)
{
// Get the address of the swap line
pStart = pData + (lineStart * lineSize);
pEnd = pData + (lineEnd * lineSize);
// Swap the top with the bottom
memcpy(pLineData, pStart, lineSize);
memcpy(pStart, pEnd, lineSize);
memcpy(pEnd, pLineData, lineSize);
// Adjust the line index
lineStart++;
lineEnd--;
}
delete pLineData;
// Set the flag to say that the callback function is finished
bCallbacked = TRUE;
return TRUE;
}
这里变量bmif是BITMAPINFOHEADER,pData是Bytes 有什么办法可以实现吗?
如果你有HBITMAP
句柄,你可以这样做:
您的图片大小使用:::GetObject(hBmp, sizeof(BITMAP), &bmpSizeInfo);
像这样填写BITMAPINFO
:
memset(&bmpData, 0, sizeof(BITMAPINFO));
bmpData.bmiHeader.biSize = sizeof(bmpData.bmiHeader);
bmpData.bmiHeader.biHeight = -bmpSizeInfo.bmHeight;
bmpData.bmiHeader.biWidth = bmpSizeInfo.bmWidth;
bmpData.bmiHeader.biPlanes = bmpSizeInfo.bmPlanes;
bmpData.bmiHeader.biBitCount = bmpSizeInfo.bmBitsPixel;
创建足够的堆内存来保存位图数据:
pBuff = new char[bmpSizeInfo.bmWidth * bmpSizeInfo.bmHeight * 4];
像这样获取位图数据:
::GetDIBits(hDc, hBmp, 0, bmpSizeInfo.bmHeight, (void*)pBuff, &bmpData, DIB_RGB_COLORS);
创建一个 D2D1_BITMAP_PROPERTIES
并像这样填充它:
bmpPorp.dpiX = 0.0f;
bmpPorp.dpiY = 0.0f;
bmpPorp.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bmpPorp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
使用您的渲染目标将数据转换为 ID2D1Bitmap
pRT->CreateBitmap(bmpSize, pBuff, 4 * bmpSizeInfo.bmWidth, bmpPorp, &pBmpFromH);
这里是如何在 Direct2D 中使用 mag 的位图。您不需要 BITMAPINFOHEADER 因为 mag 格式与 DXGI_FORMAT_B8G8R8A8_UNORM:
相同BOOL MagImageScaling(HWND hwnd, void* srcdata, MAGIMAGEHEADER srcheader, void* destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty)
{
// note: all this (dc, surface, targte) can be created only once as long as the D3D device isn't reset
ComPtr<ID2D1DeviceContext> dc;
HR(d2Device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, dc.GetAddressOf()));
ComPtr<IDXGISurface2> surface;
HR(swapChain->GetBuffer(0, IID_PPV_ARGS(&surface)));
ComPtr<ID2D1Bitmap1> target;
HR(dc->CreateBitmapFromDxgiSurface(surface.Get(), NULL, target.GetAddressOf()));
dc->SetTarget(target.Get());
D2D1_BITMAP_PROPERTIES properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
// note: this is ok as srcheader.format (GUID_WICPixelFormat32bppRGBA) is compatible
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
D2D1_SIZE_U size = {};
size.width = srcheader.width;
size.height = srcheader.height;
ComPtr<ID2D1Bitmap> bitmap;
HR(dc->CreateBitmap(size, properties, bitmap.GetAddressOf()));
HR(bitmap->CopyFromMemory(NULL, srcdata, srcheader.stride));
dc->BeginDraw();
// note: we don't call this because we draw on the whole render target
//dc->Clear();
dc->DrawBitmap(bitmap.Get());
HR(dc->EndDraw());
HR(swapChain->Present(1, 0));
return TRUE;
}