TransparentBlt for DIBs (256 color)

I need to paint DIBs transparently (by transparent color).
There is TransparentBlt for DDBs on www.codeguru.com but not for DIB. Can I convert DIB to DDB and then perform TransparentBlt? Will I lose right colors?
LVL 3
eugenemAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

chensuCommented:
What you should do is to convert a DIB to a DDB so that you get the HBITMAP and HPALETTE and pass these two handles to the TransparentBlt. And process the WM_QUERYNEWPALETTE and WM_PALETTECHANGED message sent to the top-level window. Thus you won't lose right colors.
0
eugenemAuthor Commented:
I've converted DIB to DDB using DIBToDDB function from codeguru. But now something strange happens with some colors: I set transparent color to RGB(150,255,255) but RGB(192,192,192) becames transparent. RGB(1,1,1) converts to RGB(0,0,0), but RGB(255,255,255) or RGB(128,128,128) don't convert.
I think something strange is happening in DIBToDDB.
0
chensuCommented:
I think this problem relates to the palette. Do you pass the correct palette handle to TransparentBlt?
0
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

eugenemAuthor Commented:
This doesn't matter because I use TransparentBlt with memory dc (that doesn't support palette).
0
Blondie050798Commented:
There should be a new function to draw a transparent bitmap turning up at codeguru anytime now that is more efficient when blitting to memory dcs.
0
eugenemAuthor Commented:
What new function? I use one from codeguru. I draw to memory dc to realize double-buffering.
0
eugenemAuthor Commented:
Come on, guys! I need this thing to work.
0
chensuCommented:
Try the following function. No need to convert it to a DDB.

//
// draw a DIB bitmap treating the background color of the DC as transparent
//
int TransStretchDIBits(HDC hdc,
                       WORD DstX, WORD DstY, WORD DstDX, WORD DstDY,
                       WORD SrcX, WORD SrcY, WORD SrcDX, WORD SrcDY,
                       LPVOID lpBits, LPBITMAPINFO lpbi,
                       WORD wUsage, DWORD rop)
{
    struct {
        BITMAPINFOHEADER    bih;
        WORD                aw[256];
    }   biPal;

    struct {
        BITMAPINFOHEADER    bih;
        DWORD               argb[256];
    }   biRgb;

    WORD    FAR *pw;
    DWORD   FAR *prgb;
    COLORREF rgbBk;
    HPALETTE hpal;
    WORD     wPalBk;
    WORD     wPalBlack;
    WORD     wPalWhite;
    int      i;

    //
    // see if the device supports this call directly
    //
    // otherwise we need to simulate it.
    //
#ifndef WIN32
    if (GetDeviceCaps(hdc, CAPS1) & C1_TRANSPARENT)
    {
        WORD w;
        BOOL f;

        w = SetBkMode(hdc, NEWTRANSPARENT);

        f = StretchDIBits(hdc,DstX,DstY,DstDX,DstDY,
                              SrcX,SrcY,SrcDX,SrcDY,
                              lpBits, lpbi, wUsage, rop);
        SetBkMode(hdc, w);
        return f;
    }
#endif

    //
    //  we want to do the equivelent of a MaskBlt, but we dont have to
    //  create multiple masks and things, we just change the color
    //  table of DIB, (aren't DIBs great)
    //
    //  we will use the two pass MaskBlt()
    //
    //      AND the dest with a DIB that has '1' where the trans color is
    //      '0' otherwise
    //
    //      OR the dest with a DIB that has '0' where the trans color is
    //

    rgbBk = GetBkColor(hdc);

    if (wUsage == DIB_PAL_COLORS)
    {
      // get current palette.
        hpal = SelectPalette(hdc, (HPALETTE)GetStockObject(DEFAULT_PALETTE), FALSE);
      SelectPalette(hdc, hpal, FALSE);

        // get the index of the background color (and black)
        //
        //  NOTE it is *very* important that the palette has
        //  black and white in it (*real* black and white, not
        //  PC_RESERVED or PC_NOCOLAPSE) we are doing raster op's
        //  and assume black==00, and white==FF
        //
        wPalBk    = GetNearestPaletteIndex(hpal, rgbBk);
        wPalBlack = GetNearestPaletteIndex(hpal, rgbBlack);
        wPalWhite = GetNearestPaletteIndex(hpal, rgbWhite);

        //
        //  copy the given BITMAPINFO over and munge it, to make our mask.
        //  the usage is DIB_PAL_COLORS so we need to munge index's not
        //  RGBs
       //
        biPal.bih = lpbi->bmiHeader;
        pw = (WORD FAR *)lpbi->bmiColors;

        for (i=0; i < (int)biPal.bih.biClrUsed; i++)
        {
            if (pw[i] == wPalBk)
                biPal.aw[i] = wPalWhite;
            else
                biPal.aw[i] = wPalBlack;
        }

        StretchDIBits(hdc,DstX,DstY,DstDX,DstDY,
                          SrcX,SrcY,SrcDX,SrcDY,
                          lpBits, (LPBITMAPINFO)&biPal, wUsage, DSa);

        for (i=0; i < (int)biPal.bih.biClrUsed; i++)
        {
            if (pw[i] == wPalBk)
                biPal.aw[i] = wPalBlack;
            else
                biPal.aw[i] = pw[i];

        }

        StretchDIBits(hdc,DstX,DstY,DstDX,DstDY,
                          SrcX,SrcY,SrcDX,SrcDY,
                          lpBits, (LPBITMAPINFO)&biPal, wUsage, DSx);
    }
    else
    {
        //  the usage is DIB_RGB_COLORS so we need to munge rgb's not
        //  index's
        //
        biRgb.bih = lpbi->bmiHeader;
        prgb = (DWORD FAR *)lpbi->bmiColors;

        for (i=0; i < (int)biRgb.bih.biClrUsed; i++)
        {
            if (prgb[i] == RGBQ(rgbBk))
                biRgb.argb[i] = RGBQ(rgbWhite);
            else
                biRgb.argb[i] = RGBQ(rgbBlack);
        }

        StretchDIBits(hdc,DstX,DstY,DstDX,DstDY,
                          SrcX,SrcY,SrcDX,SrcDY,
                          lpBits, (LPBITMAPINFO)&biRgb, wUsage, DSa);

        for (i=0; i < (int)biRgb.bih.biClrUsed; i++)
        {
            if (prgb[i] == RGBQ(rgbBk))
                biRgb.argb[i] = RGBQ(rgbBlack);
            else
                biRgb.argb[i] = prgb[i];
        }

        StretchDIBits(hdc,DstX,DstY,DstDX,DstDY,
                          SrcX,SrcY,SrcDX,SrcDY,
                          lpBits, (LPBITMAPINFO)&biRgb, wUsage, DSx);
    }

    return TRUE;
}

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
eugenemAuthor Commented:
How do I choose transparent color? Is it background of DC?
How do I know if I should use DIB_PAL_COLORS or DIB_RGB_COLORS?
What should be rop parameter? What's with these PS_RESERVED and PC_NOCOLLAPSE (should I make first and last 10 colors PC_NOCOLLAPSE and other zeros when I load the palette)?
0
eugenemAuthor Commented:
May be we can switch to e-mail. It will be faster.
My is mednikov@netvision.net.il.
0
chensuCommented:
>How do I choose transparent color? Is it background of DC?
Yes, use SetBkColor to set the background color of DC.

>How do I know if I should use DIB_PAL_COLORS or DIB_RGB_COLORS?
It depends on the DIB. It is the same as the parameter of StretchDIBits. It is usually DIB_RGB_COLORS.

>What should be rop parameter?
It is the same as the parameter of StretchDIBits and BitBlt. It is used only in 16-bit version. I forgot to tell you that:
#define DSa  0x008800C6L
#define DSx  0x00660046L
#define rgbBlack RGB(0,0,0)
#define rgbWhite RGB(255,255,255)

>What's with these PS_RESERVED and PC_NOCOLLAPSE (should I make first and last 10 colors PC_NOCOLLAPSE and other zeros when I load the palette)?
Normally, you need to do nothing.

>May be we can switch to e-mail. It will be faster.
Sorry, I prefer using Experts Exchange so that we can keep all the comments here.

0
eugenemAuthor Commented:
Are DSa SRCAND and DSx SRCPAINT?
I need to use this function with memory dc so should I provide palette as a parameter?
What is RGBQ? Same as RGB?
0
chensuCommented:
>Are DSa SRCAND and DSx SRCPAINT?
Actually, DSa is the same as SRCAND and DSx is the same as SRCINVERT.

>I need to use this function with memory dc so should I provide palette as a parameter?
You should select the palette of the DIB into the DC and realize it before calling this function. You should always do so when you handle a DIB.

>What is RGBQ? Same as RGB?
#define RGBQ(rgb)   RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb))
0
eugenemAuthor Commented:
How can I realize palette in memoryDC if it doesn't support palettes?
0
chensuCommented:
If it doesn't, don't do it.
0
eugenemAuthor Commented:
But is it true that memory dc doesn't support palette?
0
chensuCommented:
It depends. When you create the memory DC by using CDC::CreateCompatibleDC, it is compatible with the system display. You can always select and realize a palette no matter whether it supports or not. If it does not, simply no effect.
0
eugenemAuthor Commented:
It works great. Just need to replace
        for (i=0; i < (int)biRgb.bih.biClrUsed; i++)
        {
            if (prgb[i] == RGBQ(rgbBk))
                biRgb.argb[i] = RGBQ(rgbWhite);
            else
                biRgb.argb[i] = RGBQ(rgbBlack);
        }
to
      int size = 1 << lpbi->bmiHeader.biBitCount;

        for (i=0; i < size; i++)
        {
            if (prgb[i] == RGBQ(rgbBk) )
                biRgb.argb[i] = RGBQ(rgbWhite);
            else
                biRgb.argb[i] = RGBQ(rgbBlack);
        }
Thanks a lot!
0
eugenemAuthor Commented:
It works great. Just need to replace
        for (i=0; i < (int)biRgb.bih.biClrUsed; i++)
        {
            if (prgb[i] == RGBQ(rgbBk))
                biRgb.argb[i] = RGBQ(rgbWhite);
            else
                biRgb.argb[i] = RGBQ(rgbBlack);
        }
to
      int size = 1 << lpbi->bmiHeader.biBitCount;

        for (i=0; i < size; i++)
        {
            if (prgb[i] == RGBQ(rgbBk) )
                biRgb.argb[i] = RGBQ(rgbWhite);
            else
                biRgb.argb[i] = RGBQ(rgbBlack);
        }
Thanks a lot!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.