1

I am trying to create a C++ application which actually captures the bitmap from magnifier and render it using Direct 2d.

I am currently having the code to save the bitmap from magnifier to a file. but what I need is to do is to draw that bitmap to my window using direct 2d instead of saving it to file.

The magnifier returns image as struct in the form of MAGIMAGEHEADER and I was able to obtain BITMAPINFOHEADER and byte from it. I need to render it to a window using direct 2D.

Here is the code used to obtain the BITMAPINFOHEADER and bytes from Magnifier API

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;
}

Here the variable bmif is BITMAPINFOHEADER and pData is the Bytes Is there any way to achieve this?

trickymind
  • 557
  • 5
  • 21
  • The code has undefined behavior, as you are mixing `delete` with `malloc`. You are also using the wrong form of `delete` with the call to `new []`. It should be `delete[]`. – PaulMcKenzie Oct 11 '20 at 08:12
  • actually this code is working, but what i need to achive is diffrent.i added it to show a sample – trickymind Oct 11 '20 at 08:16
  • For Direct2D you must create a Direct2D bitmap: ID2D1Bitmap. You create that from a Direct2D render target, for example this https://learn.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-id2d1rendertarget-createbitmap(d2d1_size_u_constd2d1_bitmap_properties__id2d1bitmap) when you have pixels in memory. Where's your Direct2D code? – Simon Mourier Oct 11 '20 at 08:45
  • I haven't Completed the direct 2d code because i don't know how to convert this data to ID2D1 Bitmap. any way the code is same as one of my other question.https://stackoverflow.com/questions/63381368/direct-composition-idcompositiongaussianblureffect-throwing-access-violation-ex – trickymind Oct 11 '20 at 08:48
  • Call renderTarget.CreateBitmap with proper format (like DXGI_FORMAT_R8G8B8A8_UNORM or so) , and then bitmap.CopyFromMemory from your pixels buffer, then renderTarget.DrawBitmap – Simon Mourier Oct 11 '20 at 09:05
  • can you please give me a reference document or a small sample? – trickymind Oct 11 '20 at 09:15
  • Reference is the documentation links I gave. Provide a reproducing project with your test and we can try to make it work. – Simon Mourier Oct 11 '20 at 09:40
  • Sure i will just rearrange my code and post you the link – trickymind Oct 11 '20 at 10:12
  • My Code will be having several mistakes. but if i could make it work i might be able to recreate the CreateHostBackdropBrush() function so that i could use Acrylic blur in ordinary desktop apps. here is the link to the entire project : https://firebasestorage.googleapis.com/v0/b/quizbox-f1bb1.appspot.com/o/DirectComNoCom.zip?alt=media&token=bd537b8b-9d41-4007-a134-78ddf08bf678 – trickymind Oct 11 '20 at 10:30
  • Currently u can see the magnifier window (500x500) on one side and above that is the layer which is rendered by the directx. i need to get the content in the magnifier window as D2DBitmap and need to render it on the DirectX layer. That's it. Could you please help me?. sorry that My Code is totally a mess. i'm a newbie @ this. – trickymind Oct 11 '20 at 10:34
  • @ Simon Mourier currently i got the HBITMAP. Can you please tell me how to render it in using direct x – trickymind Oct 11 '20 at 11:42

2 Answers2

2

if you have the HBITMAP handle, you can do this: The the size of your image using: ::GetObject(hBmp, sizeof(BITMAP), &bmpSizeInfo);

fill a BITMAPINFO like this:

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;

create enough heap memory to hold the data for your bitmap:

pBuff = new char[bmpSizeInfo.bmWidth * bmpSizeInfo.bmHeight * 4];

Get the bitmap data like this:

::GetDIBits(hDc, hBmp, 0, bmpSizeInfo.bmHeight, (void*)pBuff, &bmpData, DIB_RGB_COLORS);

Create a D2D1_BITMAP_PROPERTIES and fill it like this:

bmpPorp.dpiX = 0.0f;
bmpPorp.dpiY = 0.0f;
bmpPorp.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bmpPorp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;

Using your render target turn the data into ID2D1Bitmap

pRT->CreateBitmap(bmpSize, pBuff, 4 * bmpSizeInfo.bmWidth, bmpPorp, &pBmpFromH);
Roshan M
  • 511
  • 4
  • 14
  • let me try with this – trickymind Oct 11 '20 at 10:37
  • i have already tried this method from this link:https://stackoverflow.com/questions/26566849/how-to-convert-a-image-file-loaded-in-memory-to-a-id2d1bitmap-in-c – trickymind Oct 11 '20 at 10:56
  • by the method below i was able to get the HBITMAP Handle but i wasn't able to render it using direct x: https://stackoverflow.com/questions/15930528/how-to-convert-an-array-of-pixels-to-hbitmap – trickymind Oct 11 '20 at 10:59
  • can you show your rendering code? I mean direct2D code – Roshan M Oct 11 '20 at 11:03
  • Full Code : https://firebasestorage.googleapis.com/v0/b/quizbox-f1bb1.appspot.com/o/DirectComNoCom.zip?alt=media&token=bd537b8b-9d41-4007-a134-78ddf08bf678 – trickymind Oct 11 '20 at 11:07
  • can u plz tell me how can i get bmpSizeInfo – trickymind Oct 11 '20 at 11:46
  • bmpSizeInfo is `BITMAP` struct – Roshan M Oct 11 '20 at 12:16
  • you can load a bitmap from resource `HBITMAP hBmp = NULL; BITMAP BMp; hBmp = (HBITMAP) LoadImage(NULL, "bitmap.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); ::GetObject(hBmp, sizeof(BMp), &BMp); //BMp.bmBits now points to data` – Roshan M Oct 11 '20 at 12:19
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222855/discussion-between-trickymind-and-roshan-m). – trickymind Oct 11 '20 at 12:22
1

Here is how you can use mag's bitmap with Direct2D. You don't need BITMAPINFOHEADER since mag format is the same as 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;
}
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298