Solved

TransparentBlt for DIBs (256 color)

Posted on 1998-05-21
19
993 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
  • 11
  • 7
19 Comments
 
LVL 23

Expert Comment

by:chensu
Comment Utility
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
Comment Utility
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
Comment Utility
I think this problem relates to the palette. Do you pass the correct palette handle to TransparentBlt?
0
 
LVL 3

Author Comment

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

Expert Comment

by:Blondie050798
Comment Utility
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
Comment Utility
What new function? I use one from codeguru. I draw to memory dc to realize double-buffering.
0
 
LVL 3

Author Comment

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

Accepted Solution

by:
chensu earned 200 total points
Comment Utility
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
Comment Utility
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 3

Author Comment

by:eugenem
Comment Utility
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
Comment Utility
>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
Comment Utility
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
Comment Utility
>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
Comment Utility
How can I realize palette in memoryDC if it doesn't support palettes?
0
 
LVL 23

Expert Comment

by:chensu
Comment Utility
If it doesn't, don't do it.
0
 
LVL 3

Author Comment

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

Expert Comment

by:chensu
Comment Utility
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
Comment Utility
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
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
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.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

763 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

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now