How to unlock a locked bitmap

0

I want to unlock a locked ID2D1Bitmap I have tried m_pBitmap1->Release(); but it doesn't seem to work

hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr); gives an access violation error:

"Unhandled exception at 0x00fb2a46 in dent_detection_sys.exe: 0xC0000005: Access violation reading location 0x00000024."

WICRect rcLock = { 0, 0, sc_bitmapWidth , sc_bitmapHeight };
IWICBitmapLock *pILock=NULL;
hr =pWICBitmap->Lock(&rcLock, WICBitmapLockWrite, &pILock);


hr=pRT->CreateSharedBitmap(
    IID_IWICBitmapLock,
    static_cast<void *>(pILock),
    &bp2,
    &m_pBitmap1
    ); 


hr=m_pBitmap1->Release(); 

hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr); 
c++
visual-c++
mfc
direct2d
wic
asked on Stack Overflow Jun 6, 2014 by user3715097

3 Answers

1

To unlock the WIC bitmap, release the IWICBitmapLock:

pILock->Release();

answered on Stack Overflow Jun 10, 2014 by vt. • edited Jun 12, 2014 by vt.
0

You should only release m_pBitmap1 when you don't want to use it anymore.

hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr); 
hr=m_pBitmap1->Release(); 
answered on Stack Overflow Jun 9, 2014 by zdd
0

According to the MSDN to use a shared WIC bitmap the render target type must be D2D1_RENDER_TARGET_TYPE_SOFTWARE when the render target is created.

cdemo is a structure object with basic d2d, wic, dwrite interface pointers. example: cdemo->d2d.factory->CreateSomething(), cdemo->wic.factory->CreateSomething(), cdemo->dwrite.factory->CreateSomething, cdemo->xaudio.factory->CreateSomething, etc.

cbmp is a pointer to a structure that has interfaces and properties related to a WIC bitmap

The following example does not work as is without some tweaks and typo fixes, but it can be used to demonstrate how to use wic for editing a bitmap and directly accessing pixels This code assumes that the cdemo->d2d.factory and cdemo->wic.factory are already created.

#define DEBUG_FAILED_GOTO(a,b) MessageBox(m_hwnd, a, L"FAILED", MB_OK); goto b
#define DEBUG_DISPLAY(a)       MessageBox(m_hwnd, a, L"DEBUG", MB_OK)

#define USING_SHARED_WIC_BITMAP
#define USING_WIC_RENDER_TARGET
#define USING_WICBMP_COPY_TO_D2DBMP

struct COMMON_WIC_BGRA { BYTE b, g, r, a };

struct COMMON_WIC_BMP
{

//// Miscelaneous variables
bool ready;

bool using_d2d_bmp;
bool using_shared_bmp;
bool using_render_tgt;

bool ready_d2d_bmp;
bool ready_shared_bmp;
bool ready_render_tgt;

UINT BPPPP;                                 // Bit-Per-Pixel-Per-Plane
UINT stride;                                // cbStride = row size;
UINT buff_size;                             // (org_size.y * stride);

POINT org_size, clip_TpLt, padding;
POINT cur_size, clip_BtRt;

D2D1_BITMAP_PROPERTIES          props_bmp;  // = D2D1::BitmapProperties();
D2D1_RENDER_TARGET_PROPERTIES   props_tgt;  // = D2D1::RenderTargetProperties();

WICPixelFormatGUID formatGUID;              // =  GUID_WICPixelFormat32bppPBGRA;

WICRect rc_lock;                            // the lock region, usually the entire

//// Interfaces
IWICBitmap*             ifc_bmp;            // WIC bitmap: lock and unlock bmp data;
IWICBitmapLock*         ifc_lock;           // Used to access the pixels to read/write

ID2D1RenderTarget*      ifc_render_tgt;     // Creates a d2d render target

ID2D1Bitmap*            ifc_d2d_bmp;        // creates an d2d bitmap for display
ID2D1Bitmap*            ifc_shared_bmp;     // creates a shared bitmap for display
ID2D1SolidColorBrush*   ifc_render_brush;   // This is needed for the render target  

//// Data pointers
BYTE*                   byte;               // Points to a pixel's byte; 8 bits
COMMON_WIC_BGRA*        wpixel;             // Points to a pixel; 32 bits
};

BOOL Lock_Release (COMON_WIC_BMP *cbmp);
BOOL Lock_Start (COMMON_INTERFACE_STUFF *cdemo, COMMON_WIC_BMP *cbmp, DWORD flags);

void Create_BMP_n_Stuff (
     COMMON_INTERFACE_STUFF *cdemo, 
     COMMON_WIC_BMP *cbmp, 
     int org_xsize, 
     int org_ysize)
{

DEBUG_DISPLAY(L"Gate 0-1 Open: started xxx process");

if (cbmp == NULL) { return E_FAIL; }
if (cdemo == NULL) { return E_FAIL; }

DEBUG_DISPLAY(L"Gate 0-2 Open: passed the sanity test");

HRESULT hr = S_OK;

ZeroMemory(cbmp, sizeof(COMMON_WIC_BMP));
 
// Create a Direct2D render target.
if (cdemo->d2d.hwnd_tgt == NULL)
{   
    RECT rc;

    GetClientRect(m_hwnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU((rc.right - rc.left), (rc.bottom - rc.top));

    cdemo->d2d.props_tgt      = D2D1::HwndRenderTargetProperties(m_hwnd, size);
    cdemo->d2d.props_tgt_type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;

    cdemo->d2d.props_bmp = D2D1::BitmapProperties();

    hr = cdemo->d2d.factory->CreateHwndRenderTarget(
         cdemo->d2d.props_tgt_type,
         cdemo->d2d.props_tgt,
         &cdemo->d2d.hwnd_tgt);

    if (FAILED(hr)) { goto CleanUp; }

}

DEBUG_DISPLAY(L"Gate 1 Open: hwnd_tgt created");

cbmp->ready = false; // type is: bool

// this option is compatible to D2D bitmap without conversion
cbmp->formatGUID = GUID_WICPixelFormat32bppPBGRA; // type is: WICPixelFormatGUID 

cbmp->buff_size = 0;    // type is: UINT32
cbmp->stride = 0;       // type is: UINT32

cbmp->clip_TpLt.x = 0;   // type is: POINT or POINTS
cbmp->clip_TpLt.y = 0;

cbmp->clip_BtRt.x = cbmp->org_size.x = org_xsize; // type is: POINT or POINTS
cbmp->clip_BtRt.y = cbmp->org_size.y = org_ysize;

cbmp->byte = NULL;  // type is: pointer to BYTE, BYTE*
cbmp->pixel = NULL; // type is: pointer to COMMON_WIC_BGRA, COMMON_WIC_BGRA* 

cbmp->ifc_bmp = NULL;          // type is: IWICBitmap*
cbmp->ifc_d2d_bmp = NULL;      // type is: ID2D1Bitmap*
cbmp->ifc_lock = NULL;         // type is: IWICBitmapLock*
cbmp->ifc_shared_bmp = NULL;   // type is: ID2D1Bitmap*
cbmp->ifc_render_tgt = NULL;   // type is: ID2D1RenderTarget*
cbmp->ifc_render_brush = NULL; // type is: ID2D1SolidColorBrush*

//D2D1_BITMAP_PROPERTIES        props_bmp; = D2D1::BitmapProperties();
//D2D1_RENDER_TARGET_PROPERTIES props_tgt; = D2D1::RenderTargetProperties();
//bool ready;

//bool using_d2d_bmp;
//bool using_shared_bmp;
//bool using_render_tgt;

//bool ready_d2d_bmp;
//bool ready_shared_bmp;
//bool ready_render_tgt;

//UINT BPPPP;                                   // Bit-Per-Pixel-Per-Plane

if (cdemo->wic.factory == NULL)
{   // (re)create the WIC factory
 
    hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        reinterpret_cast<void **>(&cdemo->wic.factory));

    if (FAILED(hr)) { goto CleanUp; }
}

hr = cdemo->wic.factory->CreateBitmap(
        cbmp->org_size.x,
        cbmp->org_size.y,
        cbmp->formatGUID,
        WICBitmapCacheOnDemand,
        &cbmp->ifc_bmp);

// Experimental debug
//if (FAILED(hr)) { DEBUG_FAILED_GOTO(L"FAILED creating wic bitmap", CleanUp); }

if (FAILED(hr)) { goto CleanUp; }

DEBUG_DISPLAY(L"Gate 2 Open: created the WIC bitmap");

// type is: WICRect;
cbmp->rc_lock = { 0, 0, (UINT)cbmp->org_size.x, (UINT)cbmp->org_size.y };

hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, WICBitmapLockWrite, &cbmp->ifc_lock);

hr = cbmp->ifc_lock->GetStride(&cbmp->stride);  //row size = (xsize*BPPP) + xpadding

hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);

cbmp->wpixel = (COMMON_WIC_BRGA *)cbmp->byte;

// clear the bitmap
ZeroMemory(cbmp->byte, cbmp->buff_size);

#ifdef USING_SHARED_WIC_BITMAP

cbmp->props_bmp = D2D1:BitmapProperties(); 

hr = demo->d2d.hwnd_tgt->CreateSharedBitmap(
     IID_IWICBitmapLock,
     (void*)cbmp->ifc_lock,
     &cbmp->props_bmp,
     &cbmp->ifc_shared_bmp);

if (SUCCEDED(hr)) 
{ 
    cbmp->using_shared_bmp = true; 
    
    DEBUG_DISPLAY(L"Gate 4-1 Open: created shared wic bitmap");
}

#endif

#ifdef USING_WICBMP_COPY_TO_D2DBMP

hr = cdemo->d2d.factory->CreateBitmapFromWicBitmap(
     cbmp->ifc_bmp,
     &cbmp->props_bmp, 
     &cbmp->ifc_d2d_bmp);

if (SUCCEDED(hr)) 
{ 
    cbmp->using_d2d_bmp = true; 
    
    DEBUG_DISPLAY(L"Gate 4-2 Open: created d2d bitmap ");
}

#endif

#ifdef USING_WIC_RENDER_TARGET

cbmp->props_tgt      = D2D1::RenderTargetProperties();
cbmp->props_tgt.type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;

hr = cdemo->d2d.factory->CreateWicBitmapRenderTarget(
    cbmp->ifc_bmp,
    &cbmp->props_tgt,
    &cbmp->ifc_render_tgt);

if (SUCCEDED(hr))
 {
     hr = cbmp->ifc_render_tgt->CreateSolidColorBrush(
          { 1.0f, 1.0f, 1.0f, 1.0f },  // Solid white
          &cbmp->ifc_render_brush);

     cbmp->using_shared_bmp = true; 

     DEBUG_DISPLAY(L"Gate 4-3 Open: created wic render target and brush");
 }
   
#endif

if (FAILED(hr)) { goto CleanUp; }

cbmp->ready = true;

// Rules of engagement if using all possible combinations above

// 1) After SafeRelease(&cbmp->ifc_lock) you cannot use cbmp->byte or cbmp->wpixel

// 2) To use cbmp->ifc_render_tgt you must first SafeRelease(cbmp->ifc_lock) and 
//    SafeRelease(&cbmp->ifc_shared_bmp). Later reinitialize them as needed.

// 3) To display the wic bitmap (cbmp->ifc_bmp) onto cdemo->d2d.hwnd_tgt:
//    you cannot copy the wic bitmap (cbmp->ifc_bmp) directly to an hwnd render target

//    option 1: This is whole point of creating the shared bmp     
//    cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_shared_bmp);

//    option 2: Copy the pixels to the d2d bitmap, copy the d2d bitmap to the target
//    cbmp->ifc_d2d_bmp->CopyFromMemory(cbmp->byte, &dst_rc, cbmp->stride);
//    cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp);

//    option 3: Copy from the render target to the d2d bitmap 
//    cbmp->ifc_d2d_bmp->CopyFromRenderTarget(&pt_dst, cbmp->ifc_render_tgt, &src_rc);
//    cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp); 

// 4) When drawing directly to the wic bitmap either use cbmp->ifc_render_tgt or 
//    cbmp->ifc_lock + cbmp->byte + your own algorithms to draw shapes
//  
// 5) for simplicty: it can get confusing when trying to use all methods
        option 1: use the ifc_lock with the ifc_shared_bmp + your own algorithms    
        option 2: use the ifc_render_tgt with the ifc_d2d_bmp

// Example: Draw a filled 12x15 rectangle example:

int x = 20, byte_col = 0, wpixel_col = 0, sizey = 12;
int y = 35, byte_row = 0, wpixel_row = 0, sizex = 15;

D2D1_COLOR_F d2d_colr = { 0.50f, 0.10f, 0.80f, 1.00f }; //some random color

COMMON_WIC_BGRA wic_colr = { 0, 0, 0, 0 };

D2D1_POINT_2U d2d_pt_dst_f = { 0, 0 };

D2D_RECT_F    d2d_outputrect = { 0.0f, 0.0f, 0.0f, 0.0f };

D2D1_RECT_F   d2d_dst_rcf = 
           { 0.0f, 0.0f, (FLOAT)cbmp->org_size.x, (FLOAT)cbmp->org_size.y }; 

D2D1_RECT_U   d2d_src_rcu = 
           { 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y }; 

WIC_RECT_U wic_dst_rcu =  
           { 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y }; 

WIC_RECT_U wic_src_rcu = wic_dst_rcu  

// must release the lock and shared bitmap before using the render target
Lock_End(cbmp);
    
// This should look familiar
d2d_outputrect = { (FLOAT)x, (FLOAT)y, (FLOAT)(x+sizex-1), (FLOAT)(y+sizey-1) };  

cbmp->ifc_render_tgt->BeginDraw();
cbmp->ifc_render_brush->SetColor(d2d_colr);
cbmp->ifc_render_tgt->SetTransform(D2D1::IdentityMatrix());
cbmp->ifc_render_tgt->FillRectangle(&d2d_outputrect, cbmp->ifc_render_brush);
hr = cbmp->ifc_render_tgt->EndDraw();

    
// display the wic bitmap on the hwnd render target
hr = cbmp->ifc_d2d_bmp->CopyFromRenderTarget(
     &d2d_pt_dst, 
     cbmp->ifc_render_tgt, 
     &d2d_src_rc);

hr = cdemo->d2d.hwnd_tgt->DrawBMP(&d2d_dst_rc, cbmp->ifc_d2d_bmp); 

// Alternative: using the ifc_lock with the ifc_shared_bmp + home grown algorithms

if (!Lock_Start(cdemo, cbmp, WICBitmapLockWrite)) { goto CleanUp; }
 
   
// convert D2D1_COLOR_F { b, g, r, a} to BYTE { b, g, r, a }

wic_colr.b = (BYTE)ceil(d2d_colr.b * 255);
wic_colr.g = (BYTE)ceil(d2d_colr.g * 255);
wic_colr.r = (BYTE)ceil(d2d_colr.r * 255);
wic_colr.a = (BYTE)ceil(d2d_colr.a * 255);
     
for (int run_y = 0; run_y < sizey; ++run_y)
{
    // clipping for the y values
    if (((run_y + y) < cbmp->clip_TpLt.y) || ((run_y + y) >= clip_BtRt.y)) 
    { continue; }

    // convert the y to a byte position
    byte_row = ((run_y + y) * cbmp->stride);

    wpixel_row = ((run_y + y) * cbmp->org_size.x) + cbmp->padding.x;  //optional

    for (int run_x = 0; run_x < sizex; ++run_x)
    {
        // clipping for the x values
        if (((run_x + x) < cbmp->clip_TpLt.x) || ((run_x + x) >= clip_BtRt.x)) 
        { continue; }

        // convert the x to an offset position
        byte_col = ((run_x + x) * 4); // must multiply by 4 bytes (b, g, r, a) 
            
        wpixel_col = (run_x + x);  // cbmp->wpixel points to every 4 bytes
          
        // access the pixels by means of pointer[(y_position + x_offset)]
            
        cbmp->byte[(byte_row + byte_col + 0)] = wic_colr.b;
        cbmp->byte[(byte_row + byte_col + 1)] = wic_colr.g;
        cbmp->byte[(byte_row + byte_col + 2)] = wic_colr.r;
        cbmp->byte[(byte_row + byte_col + 3)] = wic_colr.a;

        cbmp->wpixel[(wpixel_row + wpixel_col)] = wic_colr;   // Alternative

        // Another method
        cbmp->wpixel[(wpixel_row + wpixel_col)].b = wic_colr.b;   // Alternatives
        cbmp->wpixel[(wpixel_row + wpixel_col)].g = wic_colr.g;   // Alternatives
        cbmp->wpixel[(wpixel_row + wpixel_col)].r = wic_colr.r;   // Alternatives
        cbmp->wpixel[(wpixel_row + wpixel_col)].a = wic_colr.a;   // Alternatives
    }
}

// display the wic bitmap on the hwnd render target
cdemo->d2d.hwnd_tgt->DrawBMP(&dst_rc, cbmp->ifc_shared_bmp);
  
// Optionally release the lock after every use
// Lock_Release(cbmp);

return; // commnent out if cleanup is required

CleanUp:

// SafeRelease everything that needs to be released

}

BOOL Lock_Start (
     COMMON_INTERFACE_STUFF *cdemo, 
     COMMON_WIC_BMP *cbmp, 
     DWORD flags)
{
     if (cdemo == NULL) { return FALSE; }

     //if (!cdemo->ready) { CreateResouces(cdemo); }

     if (cbmp == NULL) { return FALSE; }
     
     if (cbmp->ifc_lock != NULL) { return TRUE; }

     SafeRelease(&cbmp->ifc_lock);

     hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, flags, &cbmp->ifc_lock);
     
     if (FAILED(hr)) { return FALSE; }

     hr = cbmp->ifc_lock->GetStride(&cbmp->stride);
     
     hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);
     
     cbmp->wpixel = (COMMON_WIC_BGRA *)cbmp->byte;

     // recreate the shared bitmap
     SafeRelease(&cbmp->ifc_shared_bmp);

     hr = cdemo->d2d.factory->CreateSharedBitmap(
            IID_IWICBitmapLock,
            (void*)cbmp->ifc_lock,
            &cbmp->props_bmp,
            &cbmp->ifc_shared_bmp);

     return TRUE;         
} 

BOOL Lock_Release (COMON_WIC_BMP *cbmp)
{
     if (cbmp == NULL) { return FALSE; }
     
     if (cbmp->ifc_lock == NULL) { return TRUE; }
     
     SafeRelease(&cbmp->ifc_lock);
     SafeRelease(&cbmp->ifc_shared_bmp);
     
     cbmp->byte = NULL;
     cbmp->wpixel = NULL;
     
     if (cbmp->using_render_tgt) { cbmp->ready_render_tgt = true; }
    
     return TRUE;
}
answered on Stack Overflow Oct 17, 2020 by Sempai-Dami1 • edited Oct 17, 2020 by Sempai-Dami1

User contributions licensed under CC BY-SA 3.0