Problem with Image handle and GDIPlus-VBForums
Results 1 to 11 of 11

Thread: Problem with Image handle and GDIPlus

Hybrid View

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Problem with Image handle and GDIPlus

    I have a commandbutton that reads a bitmap file and shows its picture enlarged 4 times in a Picturebox named Picture2. (There is no Picture1 yet. There is only a PictureBox named Picture2 for now)

    The enlargement is done using GDIPlus techniques.

    Here is a the code, and it works perfectly:

    Code:
    Private Sub cmdShowPic3_Click()
        
        Dim DoScale     As Boolean
        Dim Render    As Boolean
        Dim hGraphics  As Long
        Dim hMatrix   As Long
        Dim tHandle  As Long
        
        Dim destX As Long
        Dim destY As Long
        Dim destWidth   As Long
        Dim destHeight  As Long
        Dim srcX   As Long
        Dim srcY   As Long
        Dim srcWidth  As Long
        Dim srcHeight  As Long
        Dim srcRect    As RECTF
        Dim GDIplusEffectsHandle  As Long
        Dim file_name  As String
        
        Dim scalerX  As Single
        Dim scalerY  As Single
        
        Dim ZoomFactor As Long
        
        Const UnitPixel  As Long = 2&
        
        
        DoScale = True
        
        Picture2.AutoRedraw = True
        
        GDIplusEffectsHandle = 0&
        
        
        ZoomFactor = 4#
        file_name = "C:\MyFiles\MyPics\temp1\pic001.bmp"
        
        
        scalerX = ZoomFactor
        scalerY = ZoomFactor
        
        If Not DoScale Then
           ZoomFactor = 1
        End If
        
        Picture2.Height = Picture2.Height * ZoomFactor
        Picture2.Width = Picture2.Width * ZoomFactor
        
        If m_Image Then GdipDisposeImage m_Image: m_Image = 0
        If GdipLoadImageFromFile(StrPtr(file_name), m_Image) Then
             ' error; failed to load image
             Exit Sub
        End If
        If GdipCreateFromHDC(Picture2.hdc, hGraphics) Then     ' must release DC with GdipDeleteGraphics
            ' error; should never get this if passing a valid DC
            Exit Sub
        End If
        
        Call GdipSetInterpolationMode(hGraphics, RenderInterpolation.lvicHighQualityBicubic)
        Call GdipSetPixelOffsetMode(hGraphics, SmoothingModeAntiAlias)
        
        destX = 0
        destY = 0
        destWidth = 150 ' * ZoomFactor
        destHeight = 150 ' * ZoomFactor
        srcX = 0
        srcY = 0
        srcWidth = 150 ' * ZoomFactor
        srcHeight = 150 ' * ZoomFactor
        
        
        srcRect.nTop = srcY ' * ZoomFactor
        srcRect.nLeft = srcX ' * ZoomFactor
        srcRect.nHeight = srcHeight ' * ZoomFactor
        srcRect.nWidth = srcWidth ' * ZoomFactor
        
        
        If DoScale Then
                Call GdipCreateMatrix2(scalerX, 0&, 0&, scalerY, destX, destY, hMatrix)
                Render = (GdipDrawImageFX(hGraphics, m_Image, srcRect, hMatrix, GDIplusEffectsHandle, 0, UnitPixel) = 0&)
           
        Else
           GdipDrawImageRectRectI hGraphics, m_Image, destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight, UnitPixel, 0, 0, 0
        End If
        
        GdipDeleteGraphics hGraphics
        
        If hMatrix Then GdipDeleteMatrix hMatrix
        
        Picture2.Refresh
    
    End Sub
    But then I copied the above code and pasted it under another commandbutton, and tried to change it.

    The change that I need is that instead of getting the picture from a file (as in the above code), I need to get the picture from another PictureBox (named Picture1) that has been already showing a picture on the screen.

    In other words, a picture is already showing in a PictureBox named Picture1, and I need to show an enlarged copy of that (enlarged by a factor of 4) in another PictureBox named Picture2.


    Here is the new code (under a separate commandbutton):

    Code:
    Private Sub cmdShowPic5_Click()
       
        Dim DoScale     As Boolean
        Dim Render    As Boolean
        Dim hGraphics  As Long
        Dim hMatrix   As Long
        Dim tHandle  As Long
        
        Dim destX As Long
        Dim destY As Long
        Dim destWidth   As Long
        Dim destHeight  As Long
        Dim srcX   As Long
        Dim srcY   As Long
        Dim srcWidth  As Long
        Dim srcHeight  As Long
        Dim srcRect    As RECTF
        Dim GDIplusEffectsHandle  As Long
        Dim file_name  As String
        
        Dim scalerX  As Single
        Dim scalerY  As Single
        
        Dim ZoomFactor As Long
        
        Const UnitPixel  As Long = 2&
        
        
        DoScale = True
        
        Picture2.AutoRedraw = True
        Picture2.Picture = Picture1.Picture
        
        Picture2.Height = Picture1.Height * ZoomFactor
        Picture2.Width = Picture1.Width * ZoomFactor
    
        
        GDIplusEffectsHandle = 0&
        
        
        ZoomFactor = 4#
        scalerX = ZoomFactor
        scalerY = ZoomFactor
        
        If Not DoScale Then
           ZoomFactor = 1
        End If
        
        
        If m_Image Then GdipDisposeImage m_Image
      ' m_Image = Picture2.Image.hPal
        m_Image = Picture2.Image.Handle
    
        
    '    If GdipLoadImageFromFile(StrPtr(file_name), m_Image) Then
    '         ' error; failed to load image
    '         Exit Sub
    '    End If
        If GdipCreateFromHDC(Picture2.hdc, hGraphics) Then     ' must release DC with GdipDeleteGraphics
            ' error; should never get this if passing a valid DC
            Exit Sub
        End If
        
        Call GdipSetInterpolationMode(hGraphics, RenderInterpolation.lvicHighQualityBicubic)
        Call GdipSetPixelOffsetMode(hGraphics, SmoothingModeAntiAlias)
        
        destX = 0
        destY = 0
        destWidth = 150 ' * ZoomFactor
        destHeight = 150 ' * ZoomFactor
        srcX = 0
        srcY = 0
        srcWidth = 150 ' * ZoomFactor
        srcHeight = 150 ' * ZoomFactor
        
        
        srcRect.nTop = srcY ' * ZoomFactor
        srcRect.nLeft = srcX ' * ZoomFactor
        srcRect.nHeight = srcHeight ' * ZoomFactor
        srcRect.nWidth = srcWidth ' * ZoomFactor
        
        
        If DoScale Then
                Call GdipCreateMatrix2(scalerX, 0&, 0&, scalerY, destX, destY, hMatrix)
                Render = (GdipDrawImageFX(hGraphics, m_Image, srcRect, hMatrix, GDIplusEffectsHandle, 0, UnitPixel) = 0&)
           
        Else
           GdipDrawImageRectRectI hGraphics, m_Image, destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight, UnitPixel, 0, 0, 0
        End If
        
        GdipDeleteGraphics hGraphics
        
        If hMatrix Then GdipDeleteMatrix hMatrix
        
        Picture2.Refresh
       
    End Sub

    But this does NOT work, and I don't understand why.

    If you note, the main change between the above pieces of code is that in the first one there is a section like this:
    Code:
        If m_Image Then GdipDisposeImage m_Image: m_Image = 0
        If GdipLoadImageFromFile(StrPtr(file_name), m_Image) Then
             ' error; failed to load image
             Exit Sub
        End If
    And in the second piece of code, I have replaced it with this:
    Code:
        If m_Image Then GdipDisposeImage m_Image
      ' m_Image = Picture2.Image.hPal
        m_Image = Picture2.Image.Handle
    
        
    '    If GdipLoadImageFromFile(StrPtr(file_name), m_Image) Then
    '         ' error; failed to load image
    '         Exit Sub
    '    End If
    because the image handle cannot come from the file, as there is no file in here and the original picture is already showing in Picture1 and copied into Picture2 by this line of code:
    Code:
    Picture2.Picture = Picture1.Picture
    So, I assumed that I could easily get the image handle like this:
    Code:
       m_Image = Picture2.Image.hPal
    or like this:
    Code:
        m_Image = Picture2.Image.Handle
    And nothing works.

    What is it that I am missing?

    How can I fix this?

    thanks,

    Ilia

  2. #2
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    GetWindowRect()
    Posts
    12,655

    Re: Problem with Image handle and GDIPlus

    I have tried to explain to you in previous threads. The GDI+ image handle is not the same as a standard image handle. It must be created via GDI+ only.

    If you want to create a NEW GDI+ image from a picturebox .Image or .Picture property, use:
    GdipCreateBitmapFromHBITMAP Picture2.Picture.Handle, m_NewImage
    I see you are using some code from my Alpha Image Control project. You can find the GdipCreateBitmapFromHBITMAP declaration there too

    Remember to destroy, at some point, anything you create with GDI+.

    Edited:
    1) GdipDrawImageFX function only exists with v1.1 of GDI+ (typically not on XP). Any calls to it without correct version installed on user's PC will error.
    2) FYI: .hPal is a palette handle
    Last edited by LaVolpe; Feb 21st, 2012 at 01:29 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VBA Control Arrays} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Re: Problem with Image handle and GDIPlus

    Hi LaVolpe,

    Let me first thank you a lot.
    I implemented your advice, and it worked perfectly.

    Just a couple of questions if you don't mind:

    1. My PC runs Windows 7 (64 bit) and this code worked on it perfectly. I understand from your post that it should not work on a PC running XP or an earlier version of Windows. But, I guess I should be safe to assume that in future versions of Windows it should work. Do you have any other oppinion?

    In other words, had you been in my situation, would you have used this code as is, or would you have somehow changed it for BETTER future compatibility?

    Is there anything in my code that you find MESSY or un-recommendable that you would have replaced with something with a better possibility of future compatibility?

    2. I have added code to destroy the image handle as you said.
    But, I am wondering, what the risk is.

    What if I don't destroy that handle?
    What is the bad thing that can happen in that case?

    Bottom line is that when the vbp application (or the exe file) ends, all the resources will return to the operating system, so there should'nt be a major mess.
    So the risk of not destrying the image handle should be minimal. Shouldnt it?

    Please advise.

    thanks,

    Ilia

  4. #4
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    GetWindowRect()
    Posts
    12,655

    Re: Problem with Image handle and GDIPlus

    That one function (GdipDrawImageFX) will almost certainly create an error regardless of the operating system used. This is because an application manifest is needed to load v1.1 of GDI+. Without the manifest, v1.0 will always be loaded & that function doesn't exist in v1.0. I'd recommend either 1) simply don't code for GdipDrawImageFX or 2) test the version of GDI+ v1.1 before attempting to call that function. v1.1 functions should be considered optional at best

    Destroy GDI+ objects you create. If you don't you can end up crashing your application. If you continue to create without destroying and your app doesn't crash, you are wasting resources by having those things hang around. Waste enough resources and you risk "out of memory" errors
    Insomnia is just a byproduct of, "It can't be done"

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VBA Control Arrays} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Re: Problem with Image handle and GDIPlus

    Hi LaVolpe,

    In your first post (post #2) you said:

    GdipDrawImageFX function only exists with v1.1 of GDI+ (typically not on XP). Any calls to it without correct version installed on user's PC will error
    And in your latest post you said:

    test the version of GDI+ v1.1 before attempting to call that function
    Now, the thing is, I used this code including that GdipDrawImageFX and it worked perfectly.

    1. Am I correct in assuming that based on this test, it is certain that I have the proper version of GDIPlus installed on my PC?

    2. If my application is to run on any other PCs, how do I write a code to ensure that the right version of GDI+ is installed (so that if the right version is not there, I call a separate procedure to simply use the VB6's picture enlargement feature instead of my new GDI+ procedure)?

    3. If this GdipDrawImageFX does not exist in previous versions of Windows, I guess it surely will exist in future versions. My PC, running Windows 7 (64 bit) can call it and use it, so I guess future versions of Windows are not going to take this function away. Or are they?

    Please advise,

    thanks,

  6. #6
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    GetWindowRect()
    Posts
    12,655

    Re: Problem with Image handle and GDIPlus

    I haven't played with Win7 much. I simply don't have ready access to it. In Vista and below, GDI+ v1.1 won't load when GdiplusStartup is called, unless an application manifest is used to specifically define v1.1. If Win7 loads it by default; great. If you are going to use your app on older O/S, be warned.

    GdipDrawImageRectRectI exists in any version. GdipDrawImageFX is used to create visual effects like blurring, tinting, sharpening, red-eye correction, etc. Not sure if it even applies to your program
    Insomnia is just a byproduct of, "It can't be done"

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VBA Control Arrays} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Re: Problem with Image handle and GDIPlus

    The only problem left with this is that the enlargement factor is not being understood properly by this GdipDrawImageFX function.

    When I use it (as in my post #1) to enlarge the picture 4 times, it actually enlarges the image as much as 3.915 times instead.

    My post#1 code enlarges the borders of Picture2 as much as 4 times:

    Code:
        Picture2.Height = Picture2.Height * ZoomFactor
        Picture2.Width = Picture2.Width * ZoomFactor
    But, the actual image (the result of GdipDrawImageFX) is slightly smaller than that, so the Picture2 with its borders slightly bigger than the actual image displayed looks awkward.

    When I put a breakpoint and try to find the REAL magnification factor that GdipDrawImageFX has achieved, I see that it has actually enlarged the picture as much as 3.915 times (instead of 4 times), because the following code results in the best way that the picture fits within the PictureBox:

    Code:
    picture2.Width = picture1.Width * 3.915
    picture2.height = picture1.height *  3.915
    I can probably live with the slight difference in enlargement, for example 3.915 instead of 4.0 would be ok, but I have to make sure that the image fits perfectly within the borders of the PictureBox. This problem I cannot live with.

    Given that in reality the enlargement factor is not always 4, and could be different), I cannot hard-code the number 3.915 (like in the little snippet of code above)

    So, I have to do one of the following fixes:
    1. Based on the enlargement factor that I pass to this code, I somehow find/calculate/figure out the REAL enlargement factor, so that I can set the width and height of Picture2
    2. Somehow find out the actual width and height of the resulting image that comes out of this GdipDrawImageFX. There should be a way, it could output the resulting width and height.
    3. Or somehow force this GdipDrawImageFX to understand this enlargement factor correctly, and enlarge as much as this factor.

    Please note that I have tried the following, and none of them works:

    Code:
       Picture2.Height = Picture2.Picture.Height
       Picture2.Width = Picture2.Picture.Width
    Code:
       Picture2.Height = Picture2.Image.Height
       Picture2.Width = Picture2.Image.Width
    Code:
       Picture2.Height = Picture2.Picture.Height / Picture2.Image.Height * Picture2.Height
       Picture2.Width = Picture2.Picture.Width / Picture2.Image.Width * Picture2.Width
    I have also tried this:

    Code:
       Picture2.AutoSize = True
    And this does not work either. When I set the Picture2.AutoSize = True, the PictureBox Picture2 will be the same size as the original PictureBox (Picture1), which would show only 1/4 th of the enlarged picture !!

    By the way, please note that in my Post #1, there was a little bug:
    Code:
    Dim ZoomFactor As Long
    that I have ALREADY fixed as follows:
    Code:
    Dim ZoomFactor As Single
    So, this bug could not be the reason for this sizing problem.

    How do I fix this sizing problem?

    thanks,

    Ilia

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Re: Problem with Image handle and GDIPlus

    Can anybody help me on this sizing problem?

    I think that hMatrix refers to a matrix, and that the dimensions of that matrix (height and width) can be somehow retrieved. If we can retrieve those height and width from the matrix, those would be the number of pixels, and then the problem is easily solved, but I don't know how to access that matrix and retrieve the height and width from it.

    Can anybody help on this?

    thanks,

    Ilia

  9. #9
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    GetWindowRect()
    Posts
    12,655

    Re: Problem with Image handle and GDIPlus

    Some notes

    1. Picture2.Picture.Height & Width are in a scalmode call HiMetrics. You should not use this value directly without converting it to another scalemode

    2. If your picturebox has borders, you should not resize it by it's Width or Height properties. Doing so will give you the wrong values.

    For example:
    - Picture1.Width is 102 pixels using a 1 pixel border (Appearance property = 0 Flat)
    - So, the horizontal area to draw on is 100 pixels, less the 1 pixel for the left/right edges of the picturebox
    - If you multiply Picture1.Width (102) * 4 you get 408. Subtract the 2 pixels from the left/right edges & you end up with 406 pixels to draw on. The drawing surface was increased more than 4x, it should have resulted to 400, not 406

    Suggest you use this calculation to resize your picturebox. If picturebox is in a frame, change Picture2.Container.ScaleMode to vbTwips. Otherwise, it is flexible enough that your picturebox's container's scalemode should not matter. Similar algo used to zoom the height
    Code:
        Dim lBorderSize As Long
        lBorderSize = (Picture2.Width - ScaleX(Picture2.ScaleWidth, Picture2.ScaleMode, Picture2.Container.ScaleMode)) / 2
        Picture2.Width = ScaleX(Picture2.ScaleWidth, Picture2.ScaleMode, Picture2.Container.ScaleMode) * zoomFactor + lBorderSize * 2
    Insomnia is just a byproduct of, "It can't be done"

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VBA Control Arrays} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Mar 2010
    Posts
    98

    Re: Problem with Image handle and GDIPlus

    Thanks for the help.
    Everything works fine now.

    Just I am wondering how I can add the other visual improvements that this GdipDrawImageFX can provide.
    For example I know that I can add sharpness, change brightness, and change contrast, but how?

    How can I make this GdipDrawImageFX function to create these visual effects?

    thanks,

  11. #11
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    GetWindowRect()
    Posts
    12,655

    Re: Problem with Image handle and GDIPlus

    Quote Originally Posted by IliaPreston View Post
    Just I am wondering how I can add the other visual improvements that this GdipDrawImageFX can provide.
    For example I know that I can add sharpness, change brightness, and change contrast, but how?

    How can I make this GdipDrawImageFX function to create these visual effects?

    thanks,
    You are already using some of the code from my Alpha Image Control. Within that control is the GDIpEffects class. And within that class you will find the following functions you can play with or learn from
    CreateBlurEffect
    CreateBrightnessContrastEffect
    CreateColorBalanceEffect
    CreateColorCurveEffect
    CreateHueSaturationLightnessEffect
    CreateRedEyeCorrectionEffect
    CreateSharpenEffect
    CreateTintEffect
    CreateToneLevelEffect

    The above functions create the effects. Within each function are comments and links to the MSDN official documentation for that GDI+ related function. GdipDrawImageFX requires an effects handle. You must destroy that also at some point. The downside of GdipDrawImageFX, it only accepts 1 effects handle. To render more than 1 effect, you will need to buffer your image, render it with 1 effect, than render that new image with another effect, etc, etc.
    Insomnia is just a byproduct of, "It can't be done"

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {GDI+ Classes/Samples} {Unicode Open/Save Dialog} {Icon Organizer/Extractor}
    {VBA Control Arrays} {XP/Vista Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width

Survey posted by VBForums.