Solved

Alpha Blending / BNitblt'ing in VB6

Posted on 2004-10-21
1,262 Views
Last Modified: 2010-05-18
Ok, this is a follow-up to http://www.experts-exchange.com/Web/Web_Languages/PHP/Q_21165330.html 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?

Thanks
0
Question by:basiclife
    18 Comments
     
    LVL 8

    Expert Comment

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

    GetPixel
    and
    SetPixel

    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

    However...

    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
       'ignore
    else
       'Draw (set the pixel.)
    endif

    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.
    0
     
    LVL 8

    Expert Comment

    by:List244
         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:

    1641702

    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.
    0
     
    LVL 32

    Expert Comment

    by:Erick37
    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:
    http://www.vbaccelerator.com/home/VB/Type_Libraries/GDIPlus_Type_Library/article.asp

    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
       
        Show
        DoEvents
        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
        Else
            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)
       
        Me.Refresh
       
        ' 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

    0
     
    LVL 32

    Expert Comment

    by:Erick37
    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)
    0
     
    LVL 5

    Author Comment

    by:basiclife
    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...
    0
     
    LVL 8

    Expert Comment

    by:List244
    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.
    0
     
    LVL 8

    Expert Comment

    by:List244
    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.
    0
     
    LVL 32

    Expert Comment

    by:Erick37
    >>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.
    0
     
    LVL 8

    Expert Comment

    by:List244
    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.
    0
     
    LVL 5

    Author Comment

    by:basiclife
    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!!!
    0
     
    LVL 8

    Expert Comment

    by:List244
    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.
    0
     
    LVL 5

    Author Comment

    by:basiclife
    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
    0
     
    LVL 8

    Assisted Solution

    by:List244
    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.
    0
     
    LVL 8

    Expert Comment

    by:List244
    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.
    0
     
    LVL 32

    Accepted Solution

    by:
    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.

    E

    0
     
    LVL 5

    Author Comment

    by:basiclife
    Ok, guys. Thanks for the input. I'm going to go and play now. I'll get back to you some time this evening
    0
     
    LVL 32

    Expert Comment

    by:Erick37
    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)
    0
     
    LVL 5

    Author Comment

    by:basiclife
    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
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    IT, Stop Being Called Into Every Meeting

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    Suggested Solutions

    Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
    This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
    As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
    Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

    884 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

    17 Experts available now in Live!

    Get 1:1 Help Now