2010-11-24 7 views
3

J'essaie d'étirer un HBITMAP avec alpha et le dessiner à anthère hdc. J'utilise StretchDIBits, puis AlphaBlend, comme indiqué dans le code ci-dessous.Quelle pourrait être la raison pour AlphaBlend de retourner «faux»

Le problème est que AlphaBlend échoue et renvoie false.
1. Est-ce que quelqu'un sait quelle pourrait être la raison? 2. Y a-t-il un meilleur moyen d'étirer et de dessiner une image transparente?

void AnimationManager::Draw(HDC hBBDC, Instance sInstance,RECT sClientRect) 
{ 
    // sClientRect is the hwnd rect 

    int nID = GetId(sInstance.nAnemationId); 
    int nFrameindex = sInstance.nFrameIndexs; 

    HDC hdcScreen = GetDC(NULL); 
    HDC hdcMem = CreateCompatibleDC(hdcScreen); 

    BITMAP bmp; 
    PBITMAPINFO pbmi; 
    WORD cClrBits; 

    ///******************* create PBITMAPINFO *********************/// 

    GetObject(m_pAnimations[nID]->m_pFramesArray[nFrameindex]->hBmp, sizeof(bmp), &bmp); 
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
    if(cClrBits == 1) 
     cClrBits = 1; 
    else if(cClrBits <= 4) 
      cClrBits = 4; 
    else if(cClrBits <= 8) 
      cClrBits = 8; 
    else if(cClrBits <= 24) 
      cClrBits = 24; 
    else cClrBits = 32; 

    if(cClrBits != 24) 
     pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<<cClrBits)); 
    else 
     pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); 

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    pbmi->bmiHeader.biWidth = bmp.bmWidth; 
    pbmi->bmiHeader.biHeight = bmp.bmHeight; 
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
    if(cClrBits < 24) 
     pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

    pbmi->bmiHeader.biCompression = BI_RGB; 

    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits + 31)& ~31)/8 * pbmi->bmiHeader.biHeight; 
    pbmi->bmiHeader.biClrImportant = 0; 


    ///**************************end PBITMAPINFO creation *****************************************/// 


    // I checked the code to this point and it seems to be fine. The problem stasrts here: 

    ///create a pointer to the image bits 
    LPVOID lpvBits = (LPVOID)LocalAlloc(GPTR,pbmi->bmiHeader.biSizeImage); 
    GetBitmapBits(m_pAnimations[nID]->m_pFramesArray[nFrameindex]->hBmp, pbmi->bmiHeader.biSizeImage, lpvBits); 

    ///stretch 
    bool test = StretchDIBits(hdcMem,0,sClientRect.bottom,sClientRect.right, -1*sClientRect.bottom,0,0,pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biHeight, lpvBits,pbmi,DIB_RGB_COLORS, SRCCOPY); 

    ///blend 
    test = AlphaBlend(hBBDC,0,0,sClientRect.right, sClientRect.bottom,hdcMem,0,0,sClientRect.right,sClientRect.bottom,m_sBlendfunc); 


    test = DeleteDC(hdcMem); // after CreateCompatibleDC 
    test = ReleaseDC(NULL, hdcScreen); // after GetDC 

    LocalFree(pbmi); 
    LocalFree(lpvBits); 
} 
+3

Vous ne saurez pas jusqu'à ce que Windows vous le dise. Utilisez GetLastError(). –

+0

Malheureusement GetLastError n'est pas utile, et retourne toujours le code 87 indiquant un paramètre invalide. –

+0

Il n'y a pas d'appel à SelectObject. Je crois que vous devez utiliser SelectObject pour sélectionner le bitmap dans votre DC compatible. Voir l'exemple de code dans ma réponse ci-dessous. –

Répondre

0

Pourquoi utiliser StretchDIBits si AlphaBlend peut aussi étirer?

0

Je ne peux pas dire exactement pourquoi le code échoue, mais je sais par expérience récente que AlphaBlend est très pointilleux sur les formats bitmap qu'il accepte. Heureusement, je peux contribuer un code de travail, qui devrait être adaptable à d'autres circonstances.

static void DrawBitmapWithAlpha(HDC aDeviceContext,const CartoType::TBitmap* aBitmap,const CartoType::TRect& aDestRect,const CartoType::TRect& aSourceRect) 
{ 
HDC hdc = CreateCompatibleDC(aDeviceContext); 
BITMAPINFOHEADER bitmap_header; 
memset(&bitmap_header,0,sizeof(bitmap_header)); 
bitmap_header.biSize = sizeof(BITMAPINFOHEADER); 
bitmap_header.biWidth = aBitmap->Width(); 
bitmap_header.biHeight = aBitmap->Height(); 
bitmap_header.biPlanes = 1; 
bitmap_header.biBitCount = 32; 
bitmap_header.biCompression = BI_RGB; 
bitmap_header.biSizeImage = 0; 
bitmap_header.biXPelsPerMeter = 1000; 
bitmap_header.biYPelsPerMeter = 1000; 
bitmap_header.biClrUsed = 0; 
bitmap_header.biClrImportant = 0; 

void* bitmap_data = NULL; 
HBITMAP hbitmap = CreateDIBSection(hdc,(const BITMAPINFO*)&bitmap_header,DIB_RGB_COLORS,&bitmap_data,NULL,0); 

// Reflect the data vertically and change from ABGR to BGRA. 
unsigned char* dest_row = (unsigned char*)bitmap_data; 
const unsigned char* source_row = aBitmap->Data() + (aBitmap->Height() - 1) * aBitmap->RowBytes(); 
for (int y = 0; y < aBitmap->Height(); y++, dest_row += aBitmap->RowBytes(), source_row -= aBitmap->RowBytes()) 
    { 
    const unsigned char* p = source_row; 
    unsigned char* q = dest_row; 
    unsigned char* end = q + aBitmap->RowBytes(); 
    while (q < end) 
     { 
     *q++ = p[1]; 
     *q++ = p[2]; 
     *q++ = p[3]; 
     *q++ = p[0]; 
     p += 4; 
     } 
    } 
SelectObject(hdc,hbitmap); 

BLENDFUNCTION bf; 
bf.BlendOp = AC_SRC_OVER; 
bf.BlendFlags = 0; 
bf.SourceConstantAlpha = 0xFF; 
bf.AlphaFormat = AC_SRC_ALPHA; 

AlphaBlend(aDeviceContext,aDestRect.Left(),aDestRect.Top(),aDestRect.Width(),aDestRect.Height(), 
      hdc,aSourceRect.Left(),aSourceRect.Top(),aSourceRect.Width(),aSourceRect.Height(), 
      bf); 

DeleteObject(hbitmap); 
DeleteDC(hdc); 
} 

La section de départ « reflètent les données verticalement » peut facilement être modifié pour faire tout ce qui est nécessaire pour copier vos données bitmap dans le bitmap créé par CreateDIBSection.

Mon format bitmap est compatible avec Windows en ce que son nombre d'octets de ligne sera toujours le même; Si votre format bitmap n'a pas cette propriété, vous devez modifier le code pour copier les données en conséquence.

Un autre point utile: je ne pouvais pas obtenir ce travail avec bitfields; et je soupçonne en outre que vous devez fournir un bitmap 32bpp avec la compression définie sur BI_RGB.

Questions connexes