Solved

TransparentBlt for DIBs (256 color)

Posted on 1998-05-21
19
1,023 Views
Last Modified: 2013-11-20
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?
0
Comment
Question by:eugenem
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 7
19 Comments
 
LVL 23

Expert Comment

by:chensu
ID: 1313602
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313603
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
 
LVL 23

Expert Comment

by:chensu
ID: 1313604
I think this problem relates to the palette. Do you pass the correct palette handle to TransparentBlt?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Author Comment

by:eugenem
ID: 1313605
This doesn't matter because I use TransparentBlt with memory dc (that doesn't support palette).
0
 
LVL 1

Expert Comment

by:Blondie050798
ID: 1313606
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313607
What new function? I use one from codeguru. I draw to memory dc to realize double-buffering.
0
 
LVL 3

Author Comment

by:eugenem
ID: 1313608
Come on, guys! I need this thing to work.
0
 
LVL 23

Accepted Solution

by:
chensu earned 200 total points
ID: 1313609
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313610
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313611
May be we can switch to e-mail. It will be faster.
My is mednikov@netvision.net.il.
0
 
LVL 23

Expert Comment

by:chensu
ID: 1313612
>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
 
LVL 3

Author Comment

by:eugenem
ID: 1313613
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
 
LVL 23

Expert Comment

by:chensu
ID: 1313614
>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
 
LVL 3

Author Comment

by:eugenem
ID: 1313615
How can I realize palette in memoryDC if it doesn't support palettes?
0
 
LVL 23

Expert Comment

by:chensu
ID: 1313616
If it doesn't, don't do it.
0
 
LVL 3

Author Comment

by:eugenem
ID: 1313617
But is it true that memory dc doesn't support palette?
0
 
LVL 23

Expert Comment

by:chensu
ID: 1313618
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313619
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
 
LVL 3

Author Comment

by:eugenem
ID: 1313620
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

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question