Alpha Blending / BNitblt'ing in VB6

Ok, this is a follow-up to which was about using masks.

I have a white(ish) BG and a grayscale sketch. Currently, I'm able to put the sketch onto the page, using a mask to define an outline. This works well enough on a white BG but if I wanted to use, say, a light blue BG, the BG would be blue but the sketch would still appear to be on "white" so the edge of the mask would be visible.

What I really need is: To take the "whiteness" of the sketch to mean the % alpha blend, so the white bits are transparent and the black bits are opaque and the bits in the middle are halway in-between.

Is it possible and if so, how can it be done?

Who is Participating?
Hi basiclife:

After a short refresher course on matrix multiplication, I have come up with what I believe you need to do your alpha blending.  The code I posted above remains the same, but replace the matrix assignments with this:

With clrMatrix
.m(0, 0) = 1: .m(3, 0) = -0.299
.m(1, 1) = 1: .m(3, 1) = -0.587
.m(2, 2) = 1: .m(3, 2) = -0.114
.m(3, 3) = 1
.m(4, 4) = 1
End With

This matrix operation takes the grayscale value of each pixel and assigns its compliment to the alpha value.  The obvious advantage of using a matrix is speed.  The entire image is drawn with per pixel alpha adjustment without having to loop and set each value.

The result is this:
White = alpha 0 (transparent)
middle gray = alpha 128 (50% transparent)
black = alpha 255 (opaque)

The operation works on grayscale as well as full color bitmaps.

The alpha value is calculated like this:

ALPHA = 255 - ((RED * 0.299) + (GREEN * 0.587) + (BLUE * 0.114))

Give it a try and let me know how you make out.


Only way I could think of to solve this is to use:


One of two ways..

1) Maybe you know your bg color? if so:

For X = 0 to PICNAME.ScaleWidth -1 'Scalemode must be 3
   For Y = 0 to PICNAME.ScaleHeight -1 ' ^^^
      SColor = GetPixel (PICNAME.Hdc,X,Y)
      B = int(SColor/65536)
      SColor = Int(SColor - (B*65536))
      G = Int(SColor/256)
      SColor = int(SColor-(G*256))
      R = Int(Scolor)
      If R < 0 Then R = 0 'Prevent error
      If B < 0 Then B = 0
      if G < 0 then G = 0
      if GetPixel(PICNAME.Hdc,x,y) <> IGNOREDCOLOR then
          SetPixel WHERETOCOPYTO.Hdc,x,y,Rgb(R,G,B)
      End If
   Next Y
Next X

Draws everything EXCEPT that color


2) Maybe... you dont...

Now you would need to look at your R G and B values and say...

If R >= 230 and G >= 230 and b >=230 then
   'Draw (set the pixel.)

If R G and B are all 230 or above, its a whitish point.
So, now you have within 20, or you could say if all
are 200 or above ETC.
     B = int(SColor/65536)
      SColor = Int(SColor - (B*65536))
      G = Int(SColor/256)
      SColor = int(SColor-(G*256))
      R = Int(Scolor)
      If R < 0 Then R = 0 'Prevent error
      If B < 0 Then B = 0
      if G < 0 then G = 0

Understanding this.

How a color is built is like so:

Say we have a color RGB (230,12,25)

That color will be written as:


1 point for each red value = 230
256 points for each green value = 3072
and 65536 for each blue = 1638400

230+3072+1638400 = 1641702

So, we know how a color is built. To take it apart, you
must work backwords. First divide it by 65536 and see
how many even numbers you get, that is your blue.
Then, subtract that from 1641702. Now you are left
with the total of red and green. Divide that by 256,
now you have your green. Subtract out the green,
and you are left with red.

Then, always make sure nothing came out below 0,
that will just crash your program, so if you happen
to get a -1 or lower.. Tell it that it is 0.
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

You can use GDI+ to draw a bitmap to your form using alpha blending.  The following code opens a file and paints it to the form at 50% transparency.

The following code requires gdiplus.tlb which can be downloaded here:

This sample uses a matrix transform to set the entire picture to 50% transparency.  If you need a per pixel level of alpha adjustment, then this can be done too.

Here's the code:

Option Explicit

'Needed to close GDI+
Private token As Long

Private Sub Form_Load()
    Dim graphics As Long, bitmap As Long
    Dim stat As GpStatus
    Dim lHeight As Single, lWidth As Single
    Dim imgAttr As Long
    Dim clrMatrix As ColorMatrix
    Dim graMatrix As ColorMatrix
    Dim sFile As String
    Me.AutoRedraw = True
    ' Load the GDI+ Dll
    ' Very important!!
    Dim GpInput As GdiplusStartupInput
    GpInput.GdiplusVersion = 1
    If GdiplusStartup(token, GpInput) <> Ok Then
      MsgBox "Error loading GDI+!", vbCritical
      Unload Me
    End If
    ' Initialize the graphics class using Picture1.hDC
    stat = GdipCreateFromHDC(Me.hDC, graphics)
    'Load a sample bitmap with alpha channel
    sFile = "c:\lake.bmp"
    stat = GdipLoadImageFromFile(sFile, bitmap)
    'Get the height and width of the image
    If (stat = Ok) Then
        stat = GdipGetImageDimension(bitmap, lWidth, lHeight)
        Debug.Print "w = " & lWidth, "h = " & lHeight
        MsgBox "Cannot open file" & vbCrLf & sFile
    End If
    'Create storage for the image attributes struct
    stat = GdipCreateImageAttributes(imgAttr)
    'Setup the transform matrix for alpha adjustment
    clrMatrix.m(0, 0) = 1
    clrMatrix.m(1, 1) = 1
    clrMatrix.m(2, 2) = 1
    clrMatrix.m(3, 3) = 0.5 'Alpha transform (50%)
    clrMatrix.m(4, 4) = 1
    'Setup the image attributes using the color matrix
    stat = GdipSetImageAttributesColorMatrix(imgAttr, ColorAdjustTypeBitmap, 1, clrMatrix, graMatrix, ColorMatrixFlagsSkipGrays)
    'Draw the bitmap using the Image Attributes
    stat = GdipDrawImageRectRect(graphics, bitmap, 0, 0, lWidth, lHeight, 0, 0, lWidth, lHeight, UnitPixel, imgAttr)
    ' Cleanup
    Call GdipDeleteGraphics(graphics)
    Call GdipDisposeImage(bitmap)
    Call GdipDisposeImageAttributes(imgAttr)
End Sub

Private Sub Form_Unload(Cancel As Integer)
   ' Unload the GDI+ Dll
   Call GdiplusShutdown(token)
End Sub

Documentation corrections:

    ' Initialize the graphics class using The form hDC <-- Corrected (not Picture1.hDC)
    stat = GdipCreateFromHDC(Me.hDC, graphics)
    'Load a sample bitmap <-- Corrected (not using alpha info from file)
    sFile = "c:\lake.bmp"
    stat = GdipLoadImageFromFile(sFile, bitmap)
basiclifeAuthor Commented:
List244: That looks like a horrendously slow bit of code, although I'll havea  look at it, I'm hoping to be able to move the sketch smoothly across the BG.

Erick37: If I use that and the sketch has a white BG, it'll have a 50% opaque white rectangle around the sketch when I draw it so if I have a blue BG on the main screen, I'll have half-white box visible which I don't want

Thanks for the ideas guys, please keep themc oming or tell me why my objections are wrong...
Basic, try the code, it is actually quite fast.
I don't know if you tried it or just looked at
it, but go ahead and try it out. It runs for
me NEARLY at the speed of bitblt itself.
Other than that, I can not however think
of a way to do it. I like to code myself,
I don't like to use other peoples engines
and such, so I don't know if there is
one to do that.

Other than that.. you are best off
using the example I just gave you
to create a new image where the
background is turned to pure white
and just use bitblit to rid it of the pure
white color.
Oh! and what you can do, is use the second method
I gave you to make a new picture. Then use BITBLT
to move that picture across. So, you create a working
bitmap with a pure white bg, then copy it across with
bitblt. It should be pretty fast, and even if its not as
fast as you'd like it, you only have to do the method
I gave you once, the rest can be blitted.
>>If I use that and the sketch has a white BG, it'll have a 50% opaque white rectangle around the sketch

Correct...but I am working on a solution which uses a per pixel alpha value to meet your requirements of having an image which is fully transparent where white, and fully opaque where black, with varying transparencies in between.
Erick, what he wants is not fully transparent where white, but
Fully transparent when CLOSE to white. Which means, it could
just be whitish. And how I am understanding it, he wants the
rest displayed with NO transparency.
basiclifeAuthor Commented:
Nope, sorry my fault. The opposite - I want fully transparent when white and half transparent when gray (or 3/4 when 3/4 black etc...) up to opaque when black. Awkward situation, I know. I'm going to havea  play with your code now List244 although I'm guessing it'll not be quite what I'm after. Either way, as I said, you're both helping loads. Please keep it coming!!!
Okay, I see what you mean..

I can not think of a way other than pixel by pixel...
You would have to take each pixel, discover its
whiteness by RGB. Turn that to a percent, then
blend pixels together... But I am thinking that
would be a bit slow...

There is the alphablend function.. Yet, that would
do the whole image at once.

If I think of another way I'll let you know.. Otherwise
maybe Erick will get his for you.
basiclifeAuthor Commented:
Yeah you can see why this is such a b*tch ... And as you say, 3-4+ operations per pixel is REALLY slow. This is really worth > 500 points, but EE rules are absolute 8-D

The only vague idea I've had while typing this is:

If I invert the Sketch and the target area, then alpha blend, it'll do nothing for the BG? or will it make it "blacker" if it would ignore the black and blend the white, I could then invert it back afterwards
Is it all grayscale??? If so what you could do is
use bitblt and SrcAnd the picture to the form,
and ignore the mask altogether. This would make
white 100% transparent and black 100% opaque,
keeping everything inbetween between 0-100.
However, once you add color it WILL be thought
as black. Then, however, if you need color you
can do a search and copy the color over,only
having to do one action to the pixels. And if
you keep it grayscale, its all fine.
By the way by if you use colo, I mean for the picture
you are copying, the background can have all the color
you want.
basiclifeAuthor Commented:
Ok, guys. Thanks for the input. I'm going to go and play now. I'll get back to you some time this evening
One more modification. In the call to GdipSetImageAttributesColorMatrix, change the last parameter to ColorMatrixFlagsDefault.  I originally had the SkipGrays flag in there wich will not work for grayscale images, obviously.

The new line should read:
'Setup the image attributes using the color matrix
stat = GdipSetImageAttributesColorMatrix(imgAttr, ColorAdjustTypeBitmap, 1, clrMatrix, graMatrix, ColorMatrixFlagsDefault)
basiclifeAuthor Commented:
Sorry for the delay in getting back to you. Have gone with a modified version of the matrix manipulation but all comments greatly appreciated so a poijnt split unless anyone objects
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.