Page 1 of 3 123 LastLast
Results 1 to 40 of 110

Thread: [VB6] GDI+ Usage & Samples

  1. #1

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    [VB6] GDI+ Usage & Samples

    This project is a teaser to get one's feet wet. For a fully functional usercontrol that is based almost entirely on GDI+, see my alpha image control project.

    If you have questions on how to do something with GDI+ that the attached project does not do, please post your question in the Graphics portion of the forum. I do not want, nor intend that this posting become a proxy "GDI+ Forum"

    If you have questions about this project then by all means ask away. There may be a few logic errors in the project; as we find those I'll continue to update. Jump to bottom to determine when last updated.

    GDI+ is a very handy tool and many coders stay away from it because it appears difficult, at first. So, the classes in this project are aimed at easing you along a bit. GDI+ has 100's of functions and the project herein only touches a small percentage of them. But should be enough for you to get your feet wet without being overwhelmed.

    A great site for descriptions of the GDI+ API functions.

    I do plan on updating this project from time to time. Things I have knowledge on and have not yet added to the project include GDI+ paths, strings, and regions. The project does include a very complete image processing class, a rendering class, and a pens/brushes class to get you started.

    If you want the absolute minimal code to read and display an image at actual size, see post #8 below

    Name:  ScreenShot.PNG
Views: 26020
Size:  84.4 KB

    Some advantages of using GDI+
    :: Load/Save PNGs and TIFFs, even multi-page TIFFs
    :: Load and display animated GIFs
    :: Alphablending - images, lines, shapes, everything. GDI+ does not use standard RGB colors. All colors are ARGB which includes level of alphablending.
    :: Built-in niffty options like rotation, mirroring, on-the-fly pixel transformations and more
    :: No manual premultiplication of alpha values
    Some disadvantages of GDI+
    :: Crashes easy if not used properly. Objects created around other objects (i.e., images) are not actually stand-alone. GDI+ requires the source data to remain present until the GDI+ object is destroyed.
    -- Here is the MS KB Article link: http://support.microsoft.com/kb/814675
    -- The workaround is to create a DIBSection, then create a GDI+ bitmap from it and destroy the DIBSection
    -- But that workaround won't allow access to other images in a multi-image formats (GIFs, TIFFs) and 32bpp become pARGB.
    :: In IDE, can crash easily too -- like subclassing, you cannot just hit End or terminate your app from the debug window while GDI+ is running.
    :: As mentioned above, a little complicated for new users
    :: Does not support all older GDI functions. For example, you can't create an XOR pen with GDI+
    :: Requires extra steps to setup for drawing; but like anything new to you, just takes a little getting used to

    ___________________________________________________________________________
    Last Edited: Jan 21, 2010 8:50 PM GMT/Zulu
    :: Modified primarily for TIFF saving
    -- Can now save multiple images with/without attributes applied
    -- TIFF images can be saved in 1,4,8,24,32 bit depths - dependent upon source image depth
    :: Added another optional rendering quality setting when drawing: PixelOffsetMode
    :: Removed requirement of cGDIpRenderer to be passed token class during its function calls.
    -- Now entire class can be passed it one time via its AttachTokenClass method
    :: Single page TIFFs no longer cache their original source data; more memory savings
    Jan 19, 2010 2:20 AM GMT/Zulu
    :: Revamped quite a bit
    -- To reduce memory usage, PNG, BMP, & JPG no longer cache original data
    -- CloneImage routine still had some shortcomings when trying to clone without applying image attributes; fixed
    -- Fixed logic error reported by Jonney when cloning rotated images
    :: Added additional image types: imageIconPNG & imageCursorPNG to distinguish between PNGs loaded from ico/cur resources
    Jan 14, 2010 19:10 PM GMT/Zulu
    :: Found 2 memory leaks, one each in 2 different functions; fixed
    :: Changed logic when loading new images
    -- If new image then all attributes are reset automatically (were not before). Optional load flag prevents this.
    -- If multi-image format displays another image within same source; attributes remain (no change from previous logic)
    :: CreateCloneWithAttributes renamed to CreateClone. WithAttributes now an optional parameter
    :: ImageType property distinguishes between icons and cursors now
    :: Reorganized and cleaned up some routines
    :: Demo reworked a tad
    -- You can now apply multiple attributes to the same image and see results
    -- Included sample of saving a multi-page TIFF
    Jan 12, 2010 01:10 AM GMT/Zulu
    :: Added a little more functionality to the cGDIpImage class
    -- GetPixel, SetPixel, ExtraTransparentColor (similar functionality of TransparentBLT)
    :: Mirroring was off, had my constants swapped around, fixed
    :: When SaveAsOriginalFormat was applied for 32bpp alphablended bitmaps, was saved as 24bpp vs 32pp, fixed
    :: Updated demo a bit
    -- included SaveAsOriginalFormat, TransparentBLT examples
    -- included option to view any image in a multiple image format
    -- included option to view image info: size, depth, type
    Jan 11, 2010 01:30 AM GMT/Zulu
    :: Jonney helped identify a logic error when deciding whether 32bpp images use the Alpha channel and how it is used. Thanx Jonney
    ...
    Attached Files Attached Files
    Last edited by LaVolpe; Oct 26th, 2020 at 12:23 PM. Reason: updated comments
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  2. #2
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    There's problem with opening 32bpp picture.
    Offset = LBound(inArray) instead of Offset = 14& in function ProcessAlphaBitmap.

  3. #3
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Another place in LoadPicture_DIBSection
    "If ProcessAlphaBitmap(bData(), 14&, BHI.bmiHeader.biWidth, BHI.bmiHeader.biHeight) = True Then"
    should be "If ProcessAlphaBitmap(bData(), 0&, BHI.bmiHeader.biWidth, BHI.bmiHeader.biHeight) = True Then"

  4. #4

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by Jonney View Post
    Another place in LoadPicture_DIBSection
    "If ProcessAlphaBitmap(bData(), 14&, BHI.bmiHeader.biWidth, BHI.bmiHeader.biHeight) = True Then"
    should be "If ProcessAlphaBitmap(bData(), 0&, BHI.bmiHeader.biWidth, BHI.bmiHeader.biHeight) = True Then"
    Jonney, you'd have to send me a sample bitmap that it doesn't work with. I suspect you were sending the arrays that contain BitmapInfo + PixelData not a proper bitmap file format. Note my final comments in last paragraph below.

    Regarding your 2 comments

    1. When passing offset as 14 vs 0, this is required because the array being passed to that function has a BITMAPFILEHEADER attached, where the 1st 14 bytes are an additional header in front of the typical BITMAPINFO. We are passing bitmap data in a file format, not DIBSECTION format. If you noticed a couple lines before that call, you will see the pixel data is being added 54 bytes + color table, into the array. The 54 bytes are the 40 for the bitmapinfo and 14 for fileheader. So 14, is correct, not 0.
    Code:
    If GetDIBits(dDC, DIBhandle, 0&, BHI.bmiHeader.biHeight, bData(54& + clrUsed * 4&), BHI, 0&) Then
    2. And in your previous post, again, for same reasons, offset cannot be LBound(Array) because the routine should be being passed an array that contains a bitmap/DIB with the BITMAPFILEHEADER in play.

    If anything I may have misled you in the function name. It probably would be better named as LoadPicture_DIBHandle vs LoadPicture_DIBSection. The ProcessAlphaBitmap routine was not designed to pass some VB array that contains just the bitmapinfoheader and pixel data, it was designed to process bitmaps file formats. If you are using it for a custom purpose, simply add an additional 14 bytes in front of your VB array before sending it to be parsed/loaded. But the 1st 2 bytes of that 14 byte buffer you may add must contain this value: &H4D42. That is the magic number for a bitmap file. You should also populate bytes the final 8 bytes with real values and there are examples on what those values are suppose to be in several of the routines. Bottom line: All loading functions in the classes assume proper file format of whatever was passed, not portions of that file format.
    Last edited by LaVolpe; Jan 10th, 2010 at 04:52 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Attached a 32bpp BMP file
    Attached Files Attached Files

  6. #6

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Jonney, thanx for the bitmap. The issue isn't with offsets, the ProcessAlphaBitmap is identifying yours as 32bpp ARGB bitmap but GDI+ says it is 32bpp RGB (no alpha channel used). I'll have to re-examine my ARGB, pARGB loop to see what happened and why.

    Thanx again for the bug report.

    Edited: Fixed and updated zip. Note that logic was flawed twice, not only did it fail when all alpha bytes were zero, it would have failed if all alpha bytes were 255. I threw that part of the project in as a final thought. I was always annoyed that GDI+ doesn't seem to want to process 32bpp alphablended bitmaps; though in the real-world, they are hard to find..

    FYI. Why your tweaks worked. Because my routine was flawed it told GDI+ that it used the alpha channel. Since the alpha channel was all zeros, GDI+ interpretted it as a 100% transparent bitmap. The reason why changing the offsets worked for you is that the routine failed on purpose because the information retrieved was offset by -14 bytes and basically retrieved garbage. Because it failed, it simply passed it off to GDI+ to see if it could load it, which it did because the image was fine, just my logic was flawed. However, those tweaks would have prevented an alphablended bitmap from loading correctly.
    Last edited by LaVolpe; Jan 10th, 2010 at 09:26 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Your fixes are working well with 32bpp BMP and alphablended bitmap now.

  8. #8

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    A little bonus code. If you only want to render a PNG, TIFF to a DC of your choosing and render it full size, this is the minimal code you need. You could also render jpg, bmp, wmf, emf and first frame of a gif. Not all icons will be loaded by GDI+. To render at a size other than full size, you will need more GDI+ API calls.

    Edited: See post #19 & post #21 below for potentially weird behavior using GdipDrawImage.
    Code:
    Private Declare Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
    Private Declare Function GdipLoadImageFromFile Lib "GdiPlus.dll" (ByVal mFilename As Long, ByRef mImage As Long) As Long
    Private Declare Function GdipDeleteGraphics Lib "GdiPlus.dll" (ByVal mGraphics As Long) As Long
    Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hDC As Long, hGraphics As Long) As Long
    Private Declare Function GdipDrawImage Lib "GdiPlus.dll" (ByVal mGraphics As Long, ByVal mImage As Long, ByVal mX As Single, ByVal mY As Single) As Long
    Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal Image As Long) As Long
    Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
    Private Type GdiplusStartupInput
        GdiplusVersion           As Long
        DebugEventCallback       As Long
        SuppressBackgroundThread As Long
        SuppressExternalCodecs   As Long
    End Type
    
    Private Function RenderPNG(FileName As String, hDC As Long, X As Long, Y As Long) As Boolean
        On Error Resume Next
        Dim GDIsi As GdiplusStartupInput, gToken As Long, hGraphics As Long, hBitmap As Long
        GDIsi.GdiplusVersion = 1&
        GdiplusStartup gToken, GDIsi
        If Err Then
              Err.Clear
              Exit Function
        ElseIf gToken = 0& Then
             Exit Function
        End If
        On Error Goto 0
        Call GdipCreateFromHDC(hDC, hGraphics)
        If hGraphics Then
            Call GdipLoadImageFromFile(StrPtr(FileName), hBitmap)
            If hBitmap Then
                GdipDrawImage hGraphics, hBitmap, X, Y
                GdipDisposeImage hBitmap
                RenderPNG = True
            End If
            GdipDeleteGraphics hGraphics
        End If
        GdiplusShutdown gToken
    End Function
    Last edited by LaVolpe; Feb 6th, 2010 at 01:49 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9
    Fanatic Member
    Join Date
    Mar 2009
    Posts
    804

    Re: [VB6] GDI+ Usage & Samples

    Keith, thanks for sharing this fine work. Over the years I've
    learned a lot from your PSC projects and this is no exception.
    This really takes a lot of the mystery out of GDIP.

  10. #10
    Fanatic Member coolcurrent4u's Avatar
    Join Date
    Apr 2008
    Location
    *****
    Posts
    993

    Re: [VB6] GDI+ Usage & Samples

    hello,

    in the site u listed , some of them use code in c++ like this one

    http://www.com.it-berater.org/gdiplu..._functions.htm

    how do i translate this to vb


    thanks
    Last edited by coolcurrent4u; Jan 14th, 2010 at 01:19 PM.
    Programming is all about good logic. Spend more time here


    (Generate pronounceable password) (Generate random number c#) (Filter array with another array)

  11. #11

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by coolcurrent4u View Post
    hello, if the site to listed , some of them use code in c++ like this one http://www.com.it-berater.org/gdiplu..._functions.htm how do i translate this to vb
    thanks
    Just gotta know how
    Look at the PowerBasic declarations, not the C decs. They are far easier, DWORD is Long. Also use declarations in the project as a guide to help.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  12. #12
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    I didn't see Attributes being changed with a Rotation (m_Angle) in pvModifyAttributes. Does a Rotation cause Image Attribute being modified? It seems yes. A Rotation could cause changes of Image Width or Height.
    Code:
    ' Return the GDI+ image angle
    ' Attribute permanent until Destroy is called
    Public Property Get Rotation() As Single
        Rotation = m_Angle
    End Property
    Public Property Let Rotation(newVal As Single)
        If m_Angle <> newVal Then
            m_Angle = newVal
            pvModifyAttributes   'Called,but no Rotation code inside
        End If
    End Property

  13. #13

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Nice to have 2nd set of eyes.

    No, attributes are not modified when rotation is in play or not. What handles rotation is the RenderImageClassToDC function in cGDIpRenderer class. Rotation is done via a world transformation on the DC.

    So, the call to pvModifyAttributes is useless in that one spot & should be removed from that property Let statement & will do next update (a result of copy & pasting one property to the next and to the next). Will re-think a bit to see if having Rotation property non-zero has any ill effects elsewhere in the routines. If it does, then I will update sooner than later. I am thinking the answer is no, otherwise I would have seen those ill effects by now; but will think about it in my sleep tonight.

    Edited: I didn't answer both of your questions. The one regarding the size, you are very correct in that it can affect the size.

    When rendering to a DC, it isn't the code's responsibility to ensure the rotated image fits the DC area, much like any rendering routine. A simpler example is if you have a 64x64 drawing surface and load a 126x126 image and render it, it will not fit the surface. It is the coder's responsibility to dictate what dimensions the rendering should be done at.

    Now in the CloneImage routine where the image is actually rotated and/or resized, it matters very much because I am taking the responsibility of ensuring the end result is large enough for the rotated image. I admit I did take a shortcut where I resized the image to SQR(W*W + H*H) which is the maximum size any dimension can have and be able to rotate the image at any angle without chopping it off. Because that size may be larger than the actual rotated image, a fixer-upper section in that routine trims excess transparency. Now, I could have taken the time to calculate the true bounds of the non-alpha pixels and then calculated their rotated dimensions to create the end result exactly sized without the fixer-upper stuff and wouldn't require a 2nd temp image because the 1st one would have been correct from the start. But 1) I really hate trig, 2) pretty much the same amount of code to determine opacity bounds, and 3) I just wanted to draw the line on how advanced some of the functions were going to be. I took out hundreds of lines of more advanced code from this project that no-one has seen, simply because, in my opinion, it was too advanced for a "get your feet wet" type of project.
    Last edited by LaVolpe; Jan 14th, 2010 at 10:11 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  14. #14
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Since What I indicated previously,rotation don't change attributes, so I can't figure out how to save a rotated picture directly using one of the cGDIpImage functions.
    Here is a way how to save a rotated picture based on your demo:

    1. Change DoRotationExample:
    Code:
    Private Sub DoRotationExample()
    
        If cImage.Handle = 0& Then LoadResourceImage "Spider"
        cImage.Rotation = cboSample.ListIndex * 5
        RenderTheImage
        cImage.ExtraTransparentColor = cImage.GetPixel(0, 0)
        RenderTheImage 'Apply m_TransColor so that we can modify m_Attr so that we can call below codes
               '(
                'If m_Attr Then  ' any attributes to apply?
                   'Set cNewImage = New cGDIpImage
                   'CloneImage cNewImage, , , True
                   'hImage = cNewImage.Handle
                 'Else
                    'hImage = m_Image(m_SourceIndex)
                 'End If
                 ')
    
    End Sub
    2. Save the rotated picture using DoSaveExample.
    eg.Case 0: bOk = cImage.SaveAsBMP(bData(), True) to save as bmp file.

    3.If the original Boundary is 'bigger' than Boundary of after-rotated picture,then the picture will save 'rightly' else some of part will cut off.

    4.Your extra routine will need to cope with Saving the rotated picture.
    Last edited by Jonney; Jan 15th, 2010 at 07:37 AM.

  15. #15

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Jonney, thanx for the bug report.
    Regarding your previous post and rotation, there is something I need to update in multiple routines. The code is already present & suitable

    1. In the SaveAs.... routines, there is a statement that needs to be changed in each of them (except SaveAsOriginalFormat).
    From: If m_Attr Then
    To: If m_Attr <> 0& Or m_Angle <> 0! Then
    or depending on taste: If Not (m_Attr = 0& And m_Angle = 0!) Then

    2. In CloneImage, need to offset the rendering so it doesn't get chopped off; oversight.
    From: cRenderer.RenderImageClassToDC ....
    To:
    Code:
    cRenderer.RenderImageClassToDC Me, tDC, (cX - Width) \ 2, (cY - Height) \ 2, _
          Width, Height, , , , , InterpolationModeHighQualityBicubic, SmoothingModeAntiAlias
    Edited: Tweaks incorporated into latest Zip in post #1
    Last edited by LaVolpe; Jan 31st, 2010 at 10:40 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  16. #16
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by LaVolpe View Post
    Jonney, thanx for the bug report.
    Regarding your previous post and rotation, there is something I need to update in multiple routines. The code is already present & suitable

    1. In the SaveAs.... routines, there is a statement that needs to be changed in each of them (except SaveAsOriginalFormat).
    From: If m_Attr Then
    To: If m_Attr <> 0& Or m_Angle <> 0! Then
    or depending on taste: If Not (m_Attr = 0& And m_Angle = 0!) Then

    2. In CloneImage, need to offset the rendering so it doesn't get chopped off; oversight.
    From: cRenderer.RenderImageClassToDC ....
    To:
    Code:
    cRenderer.RenderImageClassToDC Me, tDC, (cX - Width) \ 2, (cY - Height) \ 2, _
          Width, Height, , , , , InterpolationModeHighQualityBicubic, SmoothingModeAntiAlias
    Yes,it works now.

  17. #17
    New Member
    Join Date
    Jan 2010
    Posts
    4

    Re: [VB6] GDI+ Usage & Samples

    Thanx.

  18. #18

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Jonney brought up a good example where the classes I supplied may not be ideal as is.

    Scenario: Loading some massive compressed image like a TIFF or JPG or PNG, for example, that is 5-10x screen size.

    Issue: Takes quite awhile for the image to eventually be displayed.

    Reasons: The classes create stand-alone images to prevent accidental GDI+ crashes if the source image is removed while the GDI+ image is bound to that source. See this link that describes the issue and workarounds by MSDN.
    1. Because of this the image file is processed (bytes read from file - potential bottleneck for massive images). The image is not processed directly from file because GDI+ has issues with many types of image formats. Therefore the bytes are sent to another routine that will handle those issues.
    2. In order to eventually create the source image, an IStream interface is created and the bytes copied to that interface so that GDIpLoadFromStream API can be used by GDI+ to load image from an array. Another potential bottleneck for massive images.
    3. The stand-alone image is a bitmap, same size and bit depth of the original, then the source is rendered into the stand-alone or a data-copy from source to stand-alone is performed. For typical sized image, this process is quick but not for massive images.
    4. Now, if scaling or attributes are applied (i.e., flipping, grayscaling, rotation, etc), GDI+ must process that massive image pixel by pixel and this will take time, no matter what.
    5. Also, if one were to use one or more of the high-quality rendering options, that time is increased yet again.

    Possible Solutions.
    1. Since these massive image sources will undoubtedly be files vs byte arrays... Create a new procedure or rework existing ones that create a GDI+ image directly from file (GDIpLoadImageFromFile API) and do not move, rename or delete the file while the GDI+ image is active. This should speed things up dramatically.
    2. Create a new procedure or rework existing ones that will create a destination sized or a maximum of screen-sized GDI+ 32bpp bitmap, then load the file using GDIpLoadImageFromFile API and render that image into the 32bpp image, releasing the image created from the file and using the 32bpp GDI+ image. This will be a bit slower than option 1 initially, but since the image used by GDI+ is now no larger than the screen, any future rendering and applied attributes will be far faster.
    3. Any tweaks to existing procedures may require tweaks to supporting procedures within the classes; so before tweaking ensure you fully understand how the classes really work.
    Note: GDIpLoadFromFile should be used for formats GDI+ handles easily: TIFF, PNG for example, not all bitmaps, icons, and not cursors.

    Just some ideas. The classes were designed for every day use and ideally handling relatively normal-sized images, say screen-size or smaller. Because the classes are designed that way, they may not be optimal for special situations and that is where you may wish to modify/tweak the code for those circumstances.
    Last edited by LaVolpe; Jan 29th, 2010 at 10:30 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  19. #19
    New Member
    Join Date
    Feb 2010
    Posts
    3

    Re: [VB6] GDI+ Usage & Samples

    Hi LaVolpe

    First I want to thank you for sharing this knowledge.

    I just want to render a full size PNG file to my Form DC using your 'Bonus Code'
    But the image displayed in my form is the mini version the original image.
    My image resolution is 787x765, the displayed one is 252x245... how come?
    I just simply copy paste your code, nothing changed.

    any tought?

  20. #20

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    I haven't a clue. Obviously GDI+ sees the image as 252x245. Maybe the image may have multiple resolutions/pages? Try loading it with the main classes in post #1, double click on the picturebox and get the image details; they may explain it and may not.

    Edited: See post #22 below for the reason
    Last edited by LaVolpe; Jan 16th, 2012 at 11:54 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  21. #21
    New Member
    Join Date
    Feb 2010
    Posts
    3

    Re: [VB6] GDI+ Usage & Samples

    I follow your instruction and the image info is:
    Image Type: PNG
    Size : 787 x 765
    Color Type : True Color + Alpha

    BTW.. i change the draw function:
    GdipDrawImage hGraphics, hBitmap, X, Y
    to:
    Call GdipGetImageBounds(hBitmap, m_Size, UnitPixel)
    Call GdipDrawImageRectRectI(hGraphics, hBitmap, 0, 0, m_Size.nWidth, m_Size.nWidth, 0, 0, m_Size.nWidth, m_Size.nHeight, UnitPixel, 0&, 0&, 0&)
    and it display the image correctly.

    Thank's

  22. #22

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Ah, so GDI+ gdipDrawImage was the culprit?

    Well, I'm glad I never use that function in real life. Always have used gdipDrawImageRectRectI since it allows much more flexibility.

    Edited: Just another thing to chalk up to GDI+'s sometimes strange behavior. There is probably a reason why it did what it did, would require a bit of research for the answer.

    Edited again. I modified post #8 to reference your #19 & #21 should someone else have a similar experience.

    Follow up: I believe the issue is with GDI+ auto-DPI scaling. Per MSDN:
    Another feature of GDI+ is that images carry around the DPI they were designed for (as in Image:GetPhysicalDimension and Bitmap:SetResolution, for example). You can use this information to scale images properly, or you can let GDI+ do it. If you don’t specify a height and width when you call DrawImage, GDI+ calculates them based on the screen’s DPI and the image’s DPI.
    GdipDrawImage does not have width/height parameters. Per reply #19 above the image reports being 787x765 but rendered at 252x245. Well, if the image's DPI property/value reported 300 DPI, then using DPI scaling formula:
    logicalSize = (physicalSize * screenDPI) / imageDPI

    Width: (787 * 96) / 300 = 251.84 rounded to 252
    Height: (765 * 96) / 300 = 244.8 rounded to 245
    So, 787x765 = 252x245 @ source image DPI of 300
    Last edited by LaVolpe; Jan 17th, 2012 at 10:44 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  23. #23
    New Member
    Join Date
    Feb 2010
    Posts
    2

    Re: [VB6] GDI+ Usage & Samples

    Thanks LaVolpe...

    This all looks very interesting. I'm working on a old old vb app which I need to get transparency working and we always resorted to using GIF files before and always wondered whether we could get true alpha channels working, this will be quite exciting to test out, especially as we can change brightness as well!

    Does GDI+ allow for blending modes? Multiply/add/screen/overlay?

  24. #24

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    GDI+ does allow this via matrices if I am understanding your question correctly. If so, it can be a little complex but not too much. In post #1, I provided a link that describes GDI+ API functions. At the link are also some examples. They are in PowerBasic syntax, but I found them fairly easy to translate to VB.

    May be worth looking at... Some functions you may want to look at (Graphics section of link): GdipMultiplyWorldTransform, GdipScaleWorldTransform, GdipSetWorldTrfansform, GdipTranslateWorldTransform. Also in the Matrix section of the link are the Matrix modification routines.

    As far as overlay goes? If you are talking about transaprency, then the classes already have that built in.

    Edited: Additional questions regarding GDI+ capabilities and usage of the functions I mentioned above should be posted in the Graphics portion of the forum.
    Last edited by LaVolpe; Feb 22nd, 2010 at 09:07 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  25. #25
    New Member
    Join Date
    Feb 2010
    Posts
    2

    Re: [VB6] GDI+ Usage & Samples

    Just one small question on your post 8 code, I'm trying to get it to load the png file into a Picturebox and don't seem to be able to find the correct syntax... (sorry it's been a while since I've dabbled in vb, moved on to more graphics based things)

  26. #26

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by GPRM_Dave View Post
    Just one small question on your post 8 code, I'm trying to get it to load the png file into a Picturebox and don't seem to be able to find the correct syntax... (sorry it's been a while since I've dabbled in vb, moved on to more graphics based things)
    You might want to make the picturebox's AutoRedraw=True. Then refresh it after the call. Note the remarks in that posting too; it is bare-bones code and offers no flexibility. You can't even get the image dimensions with it. However, you can modify the code to include more functionality. Review the main classes in post #1 and pull what you need from there, as appropriate.

    Code:
    Call RenderPNG("C:\TestImage.png", Picture1.hDC, 0, 0)
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  27. #27
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    I do believe you are adding more stuff into the class.But how about some basic tutorial for new babies like Path/Region/Pen/Brush/Font/Matrix...etc?
    Attached Images Attached Images  
    Last edited by Jonney; Mar 21st, 2010 at 10:17 PM.

  28. #28

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    I like your structure/outline. Couple things

    1. MetaFiles (nope, I don't deal with them and IMO they are rarely used (creation) vs PNGs, Bmps, etc)
    2. The Effect branch is something I'm not familiar with and haven't played with in great detail. Those effects are only available with GDI+ v2 (I believe on Vista and above). Whether it works on XP or not, I don't know.
    3. With the exception of strings, regions & paths, the other stuff is provided in various degrees of completeness. I do have a semi-complete paths class which I know you are a bit familiar with. When I find the time, I'll add it to this project. Right now, I am focused on another project at the moment.

    Note: My intention, as stated in post #1, is to get one's feet wet; not to attempt a comprehensive "how to" tutorial.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  29. #29
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Regarding GetScaledImageSizes function, if Rotation is being set,e.g. 45 degree,How to calculate the BestFit size? GetScaledImageSizes doesn't consider Rotation. In you demo,can you try to Rotation Example?part of picture will cut visually.

    How can we scale the picture to best fit the picture1.width and picture1.height with any angles rotation?
    Last edited by Jonney; May 5th, 2010 at 11:08 PM.

  30. #30
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by LaVolpe View Post
    A more effective method may be one of these:

    1. If no transparency is in effect...

    2. Transparency is different. ...
    It's a little complicated. I will probably give up until you can give a good solution.

  31. #31

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Ok, here is a routine you can tweak/add to your routines.

    First the remarks.
    1. Rotating and scaling an image relative to a destination rectangle can produce undesirable effects. For example rotating a square within the same square without having the rotated shape escape the original square's bounds, produces a rubber-band effect on the rotated shape -- changing sizes as angle changes.
    2. In most cases, I would think rubber-banding would not be desirable. For example, a clock hand rotating.

    Anyway, here is the algo that will rubberband. Adjust as needed.
    a. New form, add 2 shape controls, 1 command button
    b. Leave all controls at default names, properties, positions
    c. Copy & paste the following into the form and run it
    Code:
    Option Explicit
    
    Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    
    Private Sub Form_Load()
        Me.ForeColor = vbBlue
        With Shape1
            .Move 135, 135, 2550, 1485
        End With
        With Shape2
            .Move 3105, 135, 1485, 1485
        End With
        With Command1
            .Move 2250, 1710, 1215, 495
            .Caption = "Do It"
        End With
        Me.Move Me.Left, Me.Top, 4875, 2805
    End Sub
    
    Private Sub Command1_Click()
    
        Dim Angle As Single, A As Single, d2r As Double
        
        Dim sinT As Double, cosT As Double
        Dim h1 As Long, h2 As Long, hh As Long, ww As Long
        
        d2r = (4& * Atn(1)) / 180   ' conversion factor for degree>radian
        For A = 0 To 360
            
            Angle = Abs(A)          ' keep range between -90 to 90 for bounds calcs
            Select Case Angle
                Case Is < 91
                Case Is < 181
                    Angle = 180 - Angle
                Case Is < 271
                    Angle = Angle - 180
                Case Else
                    Angle = 360 - Angle
            End Select
            sinT = Sin(Angle * d2r)
            cosT = Cos(Angle * d2r)
            
            With Shape1
                h1 = .Height * .Height / (.Width * sinT + .Height * cosT)
                h2 = .Width * .Width / (.Width * cosT + .Height * sinT)
                If h1 < h2 Then hh = h1 Else hh = h2
                ww = hh * .Width / .Height
            End With
        
            Me.Cls
            Call ShowResults(A, ww, hh, Shape1)
            
            With Shape2
                h1 = .Height * .Height / (.Width * sinT + .Height * cosT)
                h2 = .Width * .Width / (.Width * cosT + .Height * sinT)
                If h1 < h2 Then hh = h1 Else hh = h2
                ww = hh * .Width / .Height
            End With
        
            Call ShowResults(A, ww, hh, Shape2)
            Me.Caption = A & " Degree Rotation"
            DoEvents
            Sleep 10
        
        Next
    
            Me.Caption = "Done"
    
    End Sub
    
    Private Sub ShowResults(Angle As Single, ScaledCx As Long, ScaledCy As Long, sampleShape As Shape)
        
        ' following is not part of the rotation/resizing routine
        
        Dim tPTs(1 To 4) As POINTAPI, X As Long
        Dim ctrSrc As POINTAPI, ctrDest As POINTAPI
        Dim d2r As Double
        Dim sinT As Double, cosT As Double
        
        ctrSrc.X = ScaledCx \ 2
        ctrSrc.Y = ScaledCy \ 2
        With sampleShape
            ctrDest.X = .Width \ 2 + .Left
            ctrDest.Y = .Height \ 2 + .Top
        End With
                
        d2r = (4& * Atn(1)) / 180
        sinT = Sin((Angle Mod 360) * d2r)
        cosT = Cos((Angle Mod 360) * d2r)
                
                tPTs(1).X = (-ctrSrc.X * cosT) - (-ctrSrc.Y * sinT) + ctrDest.X
                tPTs(1).Y = (-ctrSrc.X * sinT) + (-ctrSrc.Y * cosT) + ctrDest.Y
    
                tPTs(2).X = (ScaledCx - ctrSrc.X) * cosT - (-ctrSrc.Y * sinT) + ctrDest.X
                tPTs(2).Y = (ScaledCx - ctrSrc.X) * sinT + (-ctrSrc.Y * cosT) + ctrDest.Y
    
                tPTs(3).X = (ScaledCx - ctrSrc.X) * cosT - (ScaledCy - ctrSrc.Y) * sinT + ctrDest.X
                tPTs(3).Y = (ScaledCx - ctrSrc.X) * sinT + (ScaledCy - ctrSrc.Y) * cosT + ctrDest.Y
    
                tPTs(4).X = (-ctrSrc.X * cosT) - (ScaledCy - ctrSrc.Y) * sinT + ctrDest.X
                tPTs(4).Y = (-ctrSrc.X * sinT) + (ScaledCy - ctrSrc.Y) * cosT + ctrDest.Y
            
        For X = 1 To 3
            Me.Line (tPTs(X).X, tPTs(X).Y)-(tPTs(X + 1).X, tPTs(X + 1).Y)
        Next
        Me.Line (tPTs(X).X, tPTs(X).Y)-(tPTs(1).X, tPTs(1).Y)
        
    End Sub
    Edited: ww & hh would be the scaled width/height in relation to the target rectangle and angle of rotation. Rendering must be done from center of target rectangle to prevent image drawing over target bounds.

    Edited yet again. Now if you wanted to know what would be the scaled size of an image in a target rectangle so that the image can be rotated at any angle without rubberbanding, you can use this formula (refering to the GetScaledImageSizes code):
    Code:
    Dim rotSize As Long
    rotSize = Sqr(m_Size.nWidth *m_Size.nWidth + m_Size.nHeight * m_Size.nHeight)
    xRatio = destWidth / rotSize
    yRatio = destHeight / rotSize
    If xRatio > yRatio Then xRatio = yRatio
    .... rest of code
    Last edited by LaVolpe; May 8th, 2010 at 01:30 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  32. #32
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by LaVolpe View Post
    Edited yet again. Now if you wanted to know what would be the scaled size of an image in a target rectangle so that the image can be rotated at any angle without rubberbanding, you can use this formula (refering to the GetScaledImageSizes code):
    Code:
    Dim rotSize As Long
    rotSize = Sqr(m_Size.nWidth *m_Size.nWidth + m_Size.nHeight * m_Size.nHeight)
    xRatio = destWidth / rotSize
    yRatio = destHeight / rotSize
    If xRatio > yRatio Then xRatio = yRatio
    .... rest of code
    You missed considering the rotation angle? e.g. Rotate 5 degree,the image boundary is much less than picturebox size. We have to calculate the boundary of 4 corner of image with a rotation. See screenshot.
    Attached Images Attached Images  

  33. #33

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by Jonney View Post
    You missed considering the rotation angle? ...
    Nope. I gave you two options

    The first option I provided accounts for dynamic sizes and if you run the code in a test form, you will see that.

    The second option is a shortcut, its size is static. The minimum size is determined that will allow the image to be rotated at any angle. This means that the size can be larger, than needed, for some angles but will ensure all angles can be rotated within that size if rendered from the center out. In other words, the scaled size ensures the image can be rotated at any angle without rubberbanding the image.

    Edited: Here is something you can play with:
    Try the following, remarks follow the code
    1. Replace: GetScaledImageSizes
    Code:
    Public Function GetScaledImageSizes(ByVal destWidth As Long, ByVal destHeight As Long, ScaledWidth As Long, ScaledHeight As Long, _
                                            Optional ByVal CanScaleUp As Boolean = True, Optional ByVal ClipRotation As Boolean = True) As Boolean
    
        ' Function returns scaled (maintaining scale ratio) for passed destination width/height
        ' The CanScaleUp when set to false will never return scaled sizes > than 1:1
        ' The ClipRotation parameter, if False, will ensure rotated image does not exceed destination width/height
        
        If m_Image(m_SourceIndex) = 0& Then Exit Function
        
        Dim xRatio As Single, yRatio As Single
        Dim sinT As Double, cosT As Double, d2r As Double
        Dim h1 As Long, h2 As Long, A As Single
    
        xRatio = destWidth / m_Size.nWidth
        yRatio = destHeight / m_Size.nHeight
        If xRatio > yRatio Then xRatio = yRatio
        
        If Abs(Int(m_Angle + 0.99!) Mod 360) = 0! Or ClipRotation = True Then
        
            If xRatio >= 1! And CanScaleUp = False Then
                ScaledWidth = m_Size.nWidth
                ScaledHeight = m_Size.nHeight
            Else
                ScaledWidth = m_Size.nWidth * xRatio
                ScaledHeight = m_Size.nHeight * xRatio
            End If
        
        Else
    
            ScaledWidth = m_Size.nWidth * xRatio
            ScaledHeight = m_Size.nHeight * xRatio
    
            A = Abs(m_Angle)
            Select Case A
                Case Is < 91
                Case Is < 181: A = 180 - A
                Case Is < 271: A = A - 180
                Case Else: A = 360 - A
            End Select
            d2r = (4& * Atn(1)) / 180   ' conversion factor for degree>radian
            sinT = Sin(A * d2r)
            cosT = Cos(A * d2r)
    
            h1 = destHeight * destHeight / (ScaledWidth * sinT + ScaledHeight * cosT)
            h2 = destWidth * destHeight / (ScaledWidth * cosT + ScaledHeight * sinT)
            If h1 < h2 Then h2 = h1
            h1 = h2 * destWidth / destHeight
            
            If xRatio >= 1& And CanScaleUp = False Then
    
                If Not (h1 < m_Size.nWidth Or h2 < m_Size.nHeight) Then
                    ScaledWidth = m_Size.nWidth
                    ScaledHeight = m_Size.nHeight
                    GetScaledImageSizes = True
                    Exit Function
                End If
    
            End If
        
            xRatio = h1 / m_Size.nWidth
            yRatio = h2 / m_Size.nHeight
            If xRatio > yRatio Then xRatio = yRatio
            
            ScaledWidth = m_Size.nWidth * xRatio
            ScaledHeight = m_Size.nHeight * xRatio
            
        End If
        
        GetScaledImageSizes = True
    
    End Function
    Note remarks at top of new function above.

    2. Test it by hardcoding the final two parameters in the form's RenderTheImage function. Try different combinations.
    Code:
    cImage.GetScaledImageSizes sampleCx, sampleCy, Cx, Cy, False, False
    Edited: Had formula a bit hosed if destination rect is not square; changed the "h2 = " line to fix that.
    Last edited by LaVolpe; May 10th, 2010 at 02:41 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  34. #34
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    I believe he algorithm is the first release in GDI+ world and VB world. (You always create marvels in/for VB world!!!)

    On best fit mode (rotated picture will fit the canvas,will re-size the rotated picture),it works seamless.How about non-bestfit mode (picturebox force to fit rotated picture, will auto re-size the picture box)?

    scenario:
    Auto-resize canvas (e.g.picturebox) when rotating a raw size picture or fixed ratio picture. What is the algorithm to calculate new size of canvas (in this case,picture is always on center of canvas or with a fixed offset X/Y) with a rotation?

    I talks incessantly.
    Last edited by Jonney; May 11th, 2010 at 01:59 AM.

  35. #35

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Quote Originally Posted by Jonney View Post
    ...How about non-bestfit mode (picturebox force to fit rotated picture, will auto re-size the picture box)?
    Good question, try this.
    1. Add this as new function in cGDIpImage class
    Code:
    Public Sub GetScaledCanvasSize(ByVal imgWidth As Long, ByVal imgHeight As Long, ByRef CanvasWidth As Long, ByRef CanvasHeight As Long)
    
        Dim sinT As Double, cosT As Double
        Dim A As Double, d2r As Double
        Dim ctrX As Double, ctrY As Double
    
        A = Abs(Int(m_Angle) Mod 360)
        Select Case A
            Case Is < 91#
            Case Is < 181#: A = 180# - A
            Case Is < 271#: A = A - 180#
            Case Else: A = 360# - A
        End Select
        A = A + m_Angle - Int(m_Angle)
        d2r = (4# * Atn(1)) / 180#   ' conversion factor for degree>radian
        sinT = Sin(A * d2r)
        cosT = Cos(A * d2r)
        
        ctrX = imgWidth / 2#
        ctrY = imgHeight / 2#
    
        A = (-ctrX * sinT) + (-ctrY * cosT)
        CanvasHeight = (imgWidth - ctrX) * sinT + (imgHeight - ctrY) * cosT - A
        
        A = ((-ctrX * cosT) - (imgHeight - ctrY) * sinT)
        CanvasWidth = (imgWidth - ctrX) * cosT - (-ctrY * sinT) - A
    
    End Sub
    2. In the form's RenderThePicture routine, tweak to show bounding canvas size. Add this before Picture1.Refresh:
    Code:
        Dim canvasCx As Long, canvasCy As Long
        cImage.GetScaledCanvasSize Cx, Cy, canvasCx, canvasCy
        Picture1.Line (X + (Cx - canvasCx) \ 2, Y + (Cy - canvasCy) \ 2)-(X + (Cx + canvasCx) \ 2, Y + (Cy + canvasCy) \ 2), vbBlue, B
    3. You will see the canvas rectangle adjust when you rotate the image.

    Suggest selecting a rectangular, non-transparent image < 256x256 and pass CanScaleUp=False to the render function. This way you will easily see the canvas rectangle.

    Edited: The canvas rectangle would be your picturebox (question in your previous reply). However, remember that the CanvasWidth/CanvasHeight is returned in pixels and you should convert to needed scalemode to resize picturebox. Also note that you need to include any extra pixels for borders if the picturebox has borders.

    Also remember that images with transparency often have buffers of transparent pixels. This gives the illusion that the canvas rectangle is much larger than required. No algo is going to correct for that and you really only have 3 choices that I can think of: 1) accept it, 2) run a trimming routine to transfer only non-transparent pixels to another appropriately-sized image & use that image, 3) process the image to determine the tightest rectangle that excludes all fully-transparent pixels and use that size to pass to your algos (complicated because rendering offsets will most likely be necessary).
    Last edited by LaVolpe; May 11th, 2010 at 04:04 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  36. #36
    New Member
    Join Date
    May 2010
    Location
    Michigan
    Posts
    2

    Question Re: [VB6] GDI+ Usage & Samples

    Hi, I would like to make a large number of multiple shapes with the same parameters, except location (left and top) and color. Is there a way to easily make multiple rectangles, say?

    TomT

  37. #37

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    Tom, I am not sure I understand your question. If this is not related to my posted project, you should post your question in the appropriate language forum: VB6 & earlier, .Net, VBA, C++, etc, etc.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  38. #38
    New Member
    Join Date
    May 2010
    Location
    Michigan
    Posts
    2

    Re: [VB6] GDI+ Usage & Samples

    Sorry, I'm new here. I thought I was in a VB6 forum, and that my question related peripherally to the thread.

  39. #39
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [VB6] GDI+ Usage & Samples

    Code:
    Private Sub Label1_Click()
      '
      cImage.LoadPicture_stdPicture Clipboard.GetData(vbCFBitmap), cGDIplus, 1
      Call RenderTheImage
    
    End Sub
    The picture look weird with <Black> transparent color. The Return of lColorFormat in pvProcessAlphaBitmap is PixelFormat32bppARGB instead of PixelFormat32bppRGB.
    Attached Images Attached Images  

  40. #40

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Usage & Samples

    I don't know how you created the clipboard bitmap.
    Here's the only way pvProcessAlphaBitmap will return ARGB vs pARGB or RGB.
    -- One of the R,G,B values was > the alpha channel value & the alpha value is non-zero
    In that routine, you can place a break on this line: lColorFormat = PixelFormat32bppARGB
    That should help indicate that what I said above is correct.

    If it is correct and you are creating your own DIBs with CreateDIBSection API, don't assume the DIB is created with all bytes zeroed out. I have seen similar issues before in other parsing engines I've written in the past. As a matter of habit, it might be wise to call FillMemory and zero out the DIB.

    Let's say DIB was 256x256 & 32 bit.
    Code:
    Private Declare Sub FillMemory Lib "kernel32.dll" Alias "RtlFillMemory" (ByRef Destination As Any, ByVal Length As Long, ByVal Fill As Byte)
    
    Dim lSize As Long
    lSize = 256& * 256& * 4&
    FillMemory ByVal DibPtr, lSize, 0
    P.S. In that routine, RGB vs. pARGB/ARGB is only returned if ALL alpha values are either 0 or 255. It does appear the bitmap you passed is using the alpha channel, whether on purpose, accidentally, or dirty when initialized, I can't tell you.
    Last edited by LaVolpe; Jun 4th, 2010 at 01:12 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    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} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Page 1 of 3 123 LastLast

Posting Permissions

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



Click Here to Expand Forum to Full Width