Results 1 to 7 of 7

Thread: [VB] stdPicture Render (How To)

  1. #1
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 07
    Location
    GetWindowRect()
    Posts
    11,938

    [VB] stdPicture Render (How To)

    What is the .Render method of the stdPicture object and how does one use it.

    FYI: a stdPicture object is either an object declared as stdPicture or any VB .Picture/.Image property, including those of forms, image controls, pictureboxes, etc. Some other properties may be stdPicture objects too, like a command button's .DisabledPicture property or a form's .Icon property.

    The .Render method has all the benefits of VB's PaintPicture method, except one, and has a few additional benefits that VB's PaintPicture does not. In short, you have some more flexibility with .Render, but its usage is not widely known or understood.

    What does PaintPicture do that .Render cannot? It can render a stdPicture object with different raster operations, i.e., vbSrcPaint, vbSrcErase, etc. The .Render method cannot by itself. SetROP2 API can do the job though.

    What does .Render do that PaintPicture cannot? A few things
    1. It can render to any DC, memory DC, DC returned by API, or VB .hDC property (major advantage)
    2. It can render transparent GIFs, maintaining transparency (minor advantage)
    3. It is faster because less VB overhead is involved

    What APIs do PaintPicture & .Render replicate? BitBlt, StretchBlt, DrawIcon, DrawIconEx and metafile rendering. So you see, you have some powerful API replication in some common VB methods.

    Why is .Render not understood well? Because it is harder to use and PaintPicture can suffice a vast majority of the time and is easier to use. To understand .Render, you need to understand a bit about bitmaps and .Render's parameter requirements
    a. Destination parameters for .Render are in pixels
    b. Source parameters for .Render are in himetrics
    c. stdPicture objects are DIBs, stored upside down. So source parameters must be flipped vertically when rendering.

    Knowing the above, one can build a custom Render function using a stdPicture object. The following includes options for: stretching, scaling, offsetting, centering, partial rendering, and user-defined scalemodes.

    Simply copy & paste to your project. Commented well in the code.
    Tip: To make copying easier, hit the "Quote" button below & copy from that window.
    vb Code:
    1. Private Function RenderStdPicture(theTarget As Variant, thePic As StdPicture, _
    2.                              Optional ByVal destX As Long, Optional ByVal destY As Long, _
    3.                              Optional ByVal destWidth As Long, Optional ByVal destHeight As Long, _
    4.                              Optional ByVal srcX As Long, Optional ByVal srcY As Long, _
    5.                              Optional ByVal srcWidth As Long, Optional ByVal srcHeight As Long, _
    6.                              Optional ByVal ParamScaleMode As ScaleModeConstants = vbUser, _
    7.                              Optional ByVal Centered As Boolean = False, Optional ByVal ZoomFactor As Single = 1&) As Boolean
    8.                                    
    9.     ' Return Value [out]
    10.     '   If no errors occur, return value is True. If error or invalid parameters passed, value is False
    11.     ' Parameters [in]
    12.     '   theTarget: a VB form, picturebox, usercontrol or a valid hDC (no error checking for valid DC)
    13.     '       ... If Object, then it must expose a ScaleMode and hDC property
    14.     '       ... and if centering and an object, must also expose ScaleWidth & ScaleHeight properties
    15.     '   thePic: a VB ImageControl, stdPicture object, or VB .Picture property
    16.     '   destX: horizontal offset on theTarget where drawing begins, default is zero
    17.     '   destY: vertical offset on theTarget where drawing begins, default is zero
    18.     '   destWidth: rendered image width & will be multiplied against ZoomFactor; default is thePic.Width
    19.     '   destHeight: rendered image height & will be multiplied against ZoomFactor; default is thePic.Height
    20.     '   srcX: horizontal offset of thePic to begin rendering from; default is zero
    21.     '   srcY: vertical offset of thePic to begin rendering from; default is zero
    22.     '   srcWidth: thePic width that will be rendered; default is thePic.Width
    23.     '   srcHeight: thePic height that will be rendered; default is thePic.Height
    24.     '   ParamScaleMode: Scalemode for passed parameters.
    25.     '       If vbUser, then theTarget scalemode is used if theTarget is an Object else vbPixels if theTarget is an hDC
    26.     '   Centered: If True, rendered image is centered in theTarget, offset by destX and/or destY
    27.     '       If theTarget is a DC, then Centered is ignored. You must pass the correct destX,destY values
    28.     '   ZoomFactor: Scaling option. Values>1 zoom out and Values<1||>0 zoom in
    29.    
    30.     ' Tip: To stretch image to a picturebox dimensions, pass destWidth & destHeight
    31.     '   as the picturebox's scalewidth & scaleheight respectively and ZoomFactor of 1
    32.                                    
    33.     If thePic Is Nothing Then Exit Function                 ' sanity checks first
    34.     If thePic.Handle = 0& Then Exit Function
    35.     If ZoomFactor <= 0! Then Exit Function
    36.    
    37.     Dim Width As Long, Height As Long, destDC As Long
    38.    
    39.     ' the stdPicture.Render method requires vbPixels for destination and vbHimetrics for source
    40.     Width = ScaleX(thePic.Width, vbHimetric, vbPixels)      ' image size in pixels
    41.     Height = ScaleY(thePic.Height, vbHimetric, vbPixels)
    42.    
    43.     On Error Resume Next
    44.     If IsObject(theTarget) Then         ' passed object? If so, set scalemode if needed
    45.         If theTarget Is Nothing Then Exit Function
    46.         If ParamScaleMode = vbUser Then ParamScaleMode = theTarget.ScaleMode
    47.         destDC = theTarget.hDC
    48.     ElseIf IsNumeric(theTarget) Then    ' passed hDC? If so, set scalemode if needed
    49.         If ParamScaleMode = vbUser Then ParamScaleMode = vbPixels
    50.         destDC = Val(theTarget)
    51.         Centered = False                ' only applicable if theTarget is a VB object
    52.     Else
    53.         Exit Function                   ' unhandled; abort
    54.     End If
    55.     If Err Then                         ' checks above generated an error; probably passing object without scalemode property?
    56.         Err.Clear
    57.         Exit Function
    58.     End If        
    59.  
    60.     If destWidth Then                   ' calculate destination width in pixels from ParamScaleMode
    61.         destWidth = ScaleX(destWidth, ParamScaleMode, vbPixels) * ZoomFactor
    62.     Else
    63.         destWidth = Width * ZoomFactor
    64.     End If
    65.     If destHeight Then                  'calculate destination height in pixels from ParamScaleMode
    66.         destHeight = ScaleY(destHeight, ParamScaleMode, vbPixels) * ZoomFactor
    67.     Else
    68.         destHeight = Height * ZoomFactor
    69.     End If
    70.                                         ' get destX,destY in pixels from ParamScaleMode
    71.     If destX Then destX = ScaleX(destX, ParamScaleMode, vbPixels)
    72.     If destY Then destY = ScaleY(destY, ParamScaleMode, vbPixels)
    73.     If Centered Then                    ' Offset destX,destY if centering
    74.         destX = (ScaleX(theTarget.ScaleWidth, theTarget.ScaleMode, vbPixels) - destWidth) / 2 + destX
    75.         destY = (ScaleY(theTarget.ScaleHeight, theTarget.ScaleMode, vbPixels) - destHeight) / 2 + destY
    76.     End If
    77.                                         ' setup source coords/bounds and convert to vbHimetrics
    78.     If srcX Then srcX = ScaleX(srcX, ParamScaleMode, vbHimetric)
    79.     If srcY Then srcY = ScaleY(srcY, ParamScaleMode, vbHimetric)
    80.     If srcWidth Then srcWidth = ScaleX(srcWidth, ParamScaleMode, vbHimetric) Else srcWidth = thePic.Width
    81.     If srcHeight Then srcHeight = ScaleY(srcHeight, ParamScaleMode, vbHimetric) Else srcHeight = thePic.Height
    82.    
    83.     If Err Then                         ' passed bad parameters or
    84.         Err.Clear                       ' passed object that has no ScaleMode property (i.e., VB Frame)
    85.     Else
    86.         With thePic                     ' render, the "Or 0&" below are required else mismatch errors occur
    87.             .Render destDC Or 0&, destX Or 0&, destY Or 0&, destWidth Or 0&, destHeight Or 0&, _
    88.                 srcX Or 0&, .Height - srcY, srcWidth Or 0&, -srcHeight, ByVal 0&
    89.         End With                        ' return success/failure
    90.         If Err Then Err.Clear Else RenderStdPicture = True
    91.     End If
    92.     On Error GoTo 0
    93.    
    94. End Function

    Edited: Short version, no resizing, scaling, positioning, or any other options. Just draw picture at 0,0 coordinates on any DC
    Code:
       ' destDC can be any DC
        Dim thePic As stdPicture
        Set thePic = LoadPicture("C:\Images\Screenshots\image1002.jpg")
        With thePic
            .Render destDC Or 0&, 0&, 0&, ScaleX(.Width, vbHimetric, vbPixels), ScaleY(.Height, vbHimetric, vbPixels), _
                0&, .Height, .Width, -.Height, ByVal 0&
        End With
    Last edited by LaVolpe; Aug 17th, 2010 at 09:29 AM. Reason: updated comments/sample code
    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


    {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}

  2. #2
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 02
    Location
    Finland
    Posts
    6,653

    Re: [VB] stdPicture Render (How To)

    Here is a more compact solution than the Or 0&:

    Code:
    Option Explicit
    
    Dim m_Pic As StdPicture
    
    Private Sub Form_Load()
        Set m_Pic = LoadPicture(App.Path & "\Test.gif")
    End Sub
    
    Private Sub Form_Paint()
        Dim Width As Long, Height As Long
        ' convert himetric to pixels
        Width = Me.ScaleX(m_Pic.Width, vbHimetric, vbPixels)
        Height = Me.ScaleY(m_Pic.Height, vbHimetric, vbPixels)
        ' render normal
        m_Pic.Render Me.hDC, 0, 0, --Width, --Height, 0, m_Pic.Height, m_Pic.Width, -m_Pic.Height, ByVal 0&
        ' render mirrored
        m_Pic.Render Me.hDC, --Width, 100, -Width, --Height, 0, m_Pic.Height, m_Pic.Width, -m_Pic.Height, ByVal 0&
    End Sub
    It seems passing variables is somehow troublesome, I don't really understand why it would give the Type Mismatch error, but using -- is good enough to get rid of it.


    Sample attachment project here.
    Last edited by Merri; Aug 21st, 2010 at 02:59 PM.

  3. #3
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 02
    Location
    Finland
    Posts
    6,653

    Re: [VB] stdPicture Render (How To)

    Here is a short ready-to-go function and a sample attachment project. This project is especially a sample on how to draw a transparent GIF.

    Code:
    Private Sub DrawSprite(ByVal TargetDC As Long, Sprite As StdPicture, ByVal X As Long, ByVal Y As Long, Optional ByVal Center As Boolean, Optional ByVal Mirror As Boolean, Optional ByVal Flip As Boolean)
        Dim Width As Long, Height As Long
        ' convert himetric to pixels, manual edition
        Width = ((m_Sprite.Width / 2540) * 1440) \ Screen.TwipsPerPixelX
        Height = ((m_Sprite.Height / 2540) * 1440) \ Screen.TwipsPerPixelY
        ' center sprite on X & Y?
        If Center Then X = X - Width \ 2: Y = Y - Height \ 2
        ' need flip or mirror?
        If Flip Then Y = Y + Height: Height = -Height
        If Mirror Then X = X + Width: Width = -Width
        ' draw it (the -- trick fixes the Type Mismatch error)
        Sprite.Render --TargetDC, --X, --Y, --Width, --Height, _
            0, Sprite.Height, Sprite.Width, -Sprite.Height, ByVal 0&
    End Sub
    I noticed ScaleX & ScaleY throw off the pixel values a bit too much for my taste, it seems doing calculation using \ operator for the final math works faster and gives a bit nicer looking code than forcing rounding up.

    For comparison, here is the old Width & Height calculation:
    Code:
        ' convert himetric to pixels (always round up using negative for Int)
        Width = -Int(-Me.ScaleX(m_Sprite.Width, vbHimetric, vbPixels))
        Height = -Int(-Me.ScaleY(m_Sprite.Height, vbHimetric, vbPixels))
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by Merri; Aug 22nd, 2010 at 06:01 AM.

  4. #4
    VBaholic & Loving It LaVolpe's Avatar
    Join Date
    Oct 07
    Location
    GetWindowRect()
    Posts
    11,938

    Re: [VB] stdPicture Render (How To)

    Quote Originally Posted by Merri View Post
    It seems passing variables is somehow troublesome, I don't really understand why it would give the Type Mismatch error, but using -- is good enough to get rid of it.
    Any method that forces VB to re-evaluate the variables will work
    --Width
    Width Or 0&
    Width \ 1&
    etc, etc

    More compact solution? I prefer the Or 0& method. Easier to read, less confusion in my opinion & possibly less cpu cycles (though not interested to prove/disprove it).

    This is even more compact and far easier on the eyes:
    Code:
        Sprite.Render (TargetDC), (X), (Y), (Width), (Height), _
            0, Sprite.Height, Sprite.Width, -Sprite.Height, ByVal 0&
    Last edited by LaVolpe; Aug 23rd, 2010 at 08:46 AM.
    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


    {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
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 02
    Location
    Finland
    Posts
    6,653

    Re: [VB] stdPicture Render (How To)

    It isn't any shorter (same amount of characters), but it probably confuses less most people For me the Or 0& is harder to read and it probably takes longer to understand for a random guy than --. But () wins being best for the eyes. -- wins for using least pixels representing a character on the screen!

    Too bad it looks like Render is one of those hugely underused functions only because it is a little hard to deal with. Maybe I'll try do a small game without a single graphical API declaration just for the fun of it, some day

  6. #6
    New Member
    Join Date
    Nov 10
    Posts
    2

    Thumbs up Re: [VB] stdPicture Render (How To)

    Quote Originally Posted by LaVolpe View Post
    What is the .Render method of the stdPicture object and how does one use it.
    Thank you, LaVolpe and Merri, for this excellent lesson!

  7. #7
    Hyperactive Member
    Join Date
    Oct 08
    Posts
    269

    Re: [VB] stdPicture Render (How To)

    Can someone explain WHY it can't take LONG datatype variables directly as input, without any of this funny business? Clearly a number of the parameters are "As Long" (when you type out the function and hit space or comma it shows what it is expecting as input INCLUDING the data types). So why does passing them Long type variables cause this error. This is the ONLY function that has the issue of not accepting the very data type it claims to be expecting. Please explain what is going on here.

Posting Permissions

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