Link to home
Start Free TrialLog in
Avatar of debrunson
debrunson

asked on

Cannot create IWICBitmap from ID2D1Bitmap

I am reading pixel data from a buffer which is loaded by a camera.  I am able to successfully create an ID2D1Bitmap from this pixel data.  However, I cannot seem to create an IWICBitmap from the ID2D1Bitmap.  Here is the code I am using.  This function "ImgFromPixelArray" is called when a camera frame has been loaded into the pixel buffer.  The pass parameters are:

W = Width of image
H = Height of image
Stride = Stride of image
PF = pixelformat
PixelArray = address of pixel buffer

Elsewhere in the app, I (successfully) create a D2D1Factory (called mpD2DFact) which in turn creates the HwndRenderTarget used below, called mpRTarg.  I also create IWICImagingFactory elsewhere in the class called mpWICFactory, which is also used below.

BOOL CViewerPlus::ImgFromPixelArray(DWORD W, DWORD H, int Stride, UINT PF, char* PixelArray)
{
    BYTE* Addr = (BYTE*)PixelArray;

    //Create a D2D1_SIZE_U struct using the size of the bitmap.
    D2D1_SIZE_U Size = D2D1::SizeU(W, H);

    //Release the pointer to the ID2D1Bitmap and NULL it out if it has already been defined.
    if (mpImgD2D != NULL)
      mpImgD2D->Release();
    mpImgD2D = NULL;

     //Use the render target to create the ID2D1Bitmap called mpImgD2D.
    HRESULT hr = mpRTarg->CreateBitmap(Size, (void*)PixelArray, Stride, mBmpProp, &mpImgD2D);
    //The above returns hr = S_OK

    //Now create a temporary IWICBitmap object.  At the moment, this temporary bitmap  
    //will be empty, but is created in the right size and format for us to use.
    IWICBitmap *WICBmp;
    D2D1_SIZE_U ImgSize = mpImgD2D->GetPixelSize();
    hr = mpWICFactory->CreateBitmap(ImgSize.width, ImgSize.height, GUID_WICPixelFormat32bppBGR, WICBitmapCacheOnLoad, &WICBmp);
    //The above returns hr = S_OK

    //Now we create a Direct2D render target based on our temporary WIC bitmap.
    ID2D1RenderTarget *WICRTarg;
    hr = mpD2DFact->CreateWicBitmapRenderTarget(WICBmp, D2D1::RenderTargetProperties(), &WICRTarg);
    //The above returns hr = S_OK

    //Now draw D2D1Bitmap image using the WIC render target, this should write the image
    //into the WICBitmap;
    WICRTarg->BeginDraw();
    WICRTarg->DrawBitmap(mpImgD2D);
    hr = WICRTarg->EndDraw();
    //The above returns hr = 0x88990015

    return 0;
}

Open in new window


The very last step is the one that fails, and I believe that the returned error 0x88990015 indicates "The resource was realized on the wrong render target."  

If I change the code around so that the ID2D1Bitmap (mpImgD2D) is created by the WICRenderTarget (WICRTarg) rather than the HwndRenderTarget (mpRTarg), then the code works - I can draw the ID2D1Bitmap (mpImgD2D) on the IWICBitmap (WICBmp).  However, doing so prevents me from drawing mpImgD2D on the screen elsewhere in the app using the HwndRenderTarget.

So the problem is fundamentally this:  If you create an ID2D1Bitmap with a HwndRenderTarget, you can't draw that Bitmap on an IWICBitmap using a different render target (in this case, the WICBitmapRenderTarget).  And conversely, if you create an ID2D1Bitmap with a WICBitmapRenderTarget, then you can't draw it on the screen using a HwndRenderTarget.  SO, if you have an image, and need to go back and forth between an ID2D1Bitmap format (for screen display) and an IWICBitmap format (for reading and writing to disk), how do you do it?

Thank you very much.
Avatar of George Tokas
George Tokas
Flag of Greece image

The obvious workaround would have been to create a pair of d2d images one to work with display and one to work for other purposes...
So have the main image for the most important task and create a secondary clone of it when needed for other secondary tasks.

George Tokas.
P.S. Not yet that deep to d2d that's and why I can't be more specific.
Avatar of debrunson
debrunson

ASKER

So far that's all I can come up with as well.  

Surely there is a way to do the following:
a.  Read a WICBitmap from a file (I can do this)
b.  Convert that WICBitmap to a D2D1Bitmap (I can do this)
c.  Display (and manipulate) the D2D1Bitmap (I can do this too)
d.  Convert the manipulated D2D1Bitmap back into a WICBitmap for storage (I can't do this)

Am I missing something?  Or, perhaps you are supposed to load, manipulate, and store the WICBitmap, converting to D2D1Bitmap only for display?
ASKER CERTIFIED SOLUTION
Avatar of George Tokas
George Tokas
Flag of Greece image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I think you must be correct.  Unforunately with my limited IQ, I do not immediately see how to reverse the process of converting a WICBitmap to a D2D1Bitmap.  It currently appears to be a one-way trip, like jumping out of an airplane with a parachute.  However I also think that the best thing to do is to keep everything in WICBitmap form until time to throw it on the screen.  I will give you the points but reserve the right to ask more questions!
What I didn't mention in the story I shared is that I was under constant supervision of my late father when I was climb down the tree and the same was my son from me...
Now for the right to ask more questions, that is why we are all here...
The reason I mentioned that the best way is the one you describe is because all operations are in memory and those are faster since there is no delay for displaying reasons.
Now if the conversion from the memory side (WICBitmap) to the display side is fast enough then there will be no performance issues...
Another thing now:
At this time I am dealing with LAN capture-transmit-receive-displaying solution based on mpeg encoding/decoding...
As you can see I am dealing with almost the same thing and there is allways the reverse order even though it was hell to work with with visual c++ when the code library was made with mingw...
If I can help just send me a mail if I don't see your question(s).

George Tokas.