Android Question B4XImageView ResizeMode Help

walterf25

Expert
Licensed User
Longtime User
Hi Everyone, it's been a while, I need some help figuring out how to work with the B4XIMageView different resize modes, I have an app where I am using a custom wrapped library that detects certain landmarks in the body, for example, eyes, shoulders, elbows, waist, knees etc.

If I use resizeMode = FIT, I can work out the math to position a few sliders right at the detected landmarks, but I noticed that the FIT mode shows the image a little too small on some devices, and I want the image to show up big enough to fit inside the available space which is between a panel on the top and a button on the bottom of the screen.

My question is what is the difference between FIT and FILL modes, internally how does the B4XImageView resizes the image, are there any x or y offsets that can be extracted, which is the only thing I can think of that changes, and in my case I believe I need to find those values so I can position the sliders accurately.

By the way the library that detects the landmarks returns normalized values 0 to 1 which is why I need to work out the math to screen coordinates so I can position the sliders at the correct locations, as mentioned when resizeMode = FIT the math works but in FILL mode the sliders are placed above the head and under the feet, please take a look at the image attached.

Here's also the relevant code

SliderPosition:
                    Dim dp As DrawParams = Common.CalcDrawParams(imgMainSideHeight, bmp, True)
                   
                    ' --- Place sliders using normalized Y values ---
                    Common.PlaceSliderWithParams(imgMainSideHeight, pnlSideImageParent, H1SideHeight.GetBase, headTopLM.getY, dp, True)
                    Common.PlaceSliderWithParams(imgMainSideHeight, pnlSideImageParent, H2SideHeight.GetBase, feetLM.getY, dp, True)

And here are the 2 functions used on the code above

helpers:
' Compute draw params for either FIT or FILL (all DIP)
Public Sub CalcDrawParams(xiv As B4XImageView, bmp As B4XBitmap, isFill As Boolean) As DrawParams
    Dim VW As Float = xiv.mBase.Width
    Dim VH As Float = xiv.mBase.Height
    Dim IW As Float = bmp.Width / xui.Scale
    Dim IH As Float = bmp.Height / xui.Scale

    Dim s As Float
    If isFill Then
        s = Max(VW / IW, VH / IH)    ' AspectFill
    Else
        s = Min(VW / IW, VH / IH)    ' AspectFit
    End If

    Dim dispW As Float = IW * s
    Dim dispH As Float = IH * s
    Dim offX As Float = (VW - dispW) / 2   ' note: negative in FILL if dispW > VW
    Dim offY As Float = (VH - dispH) / 2   ' note: negative in FILL if dispH > VH

    Dim p As DrawParams
    p.Initialize
    p.s = s
    p.offX = offX
    p.offY = offY
    p.dispW = dispW
    p.dispH = dispH

    Return p
End Sub

' Place a horizontal slider using the params (works in FIT or FILL)
Public Sub PlaceSliderWithParams(xiv As B4XImageView, hostParent As B4XView, _
                                 slider As B4XView, normY As Float, p As DrawParams, isFill As Boolean)
    normY = Max(0, Min(1, normY))

    Dim VW As Float = xiv.mBase.Width
    Dim VH As Float = xiv.mBase.Height

    Dim baseLeft As Float = hostParent.Left + xiv.mBase.Left
    Dim baseTop  As Float = hostParent.Top  + xiv.mBase.Top

    Dim centerY As Float

    If isFill = False Then
        ' FIT (AspectFit): letterboxed; use dp.offY/dispH directly
        Dim visTop As Float = baseTop + p.offY       ' offY >= 0
        centerY = visTop + normY * p.dispH

        slider.Left = baseLeft + p.offX
        slider.Width = p.dispW
    Else
        ' FILL (AspectFill): cropped; map full-image normY into the visible slice [0..1] of the view height
        ' Compute crop in normalized-image units
        Dim cropTopNorm As Float = -p.offY / p.dispH
        Dim cropBottomNorm As Float = (VH - p.offY) / p.dispH
        cropTopNorm = Max(0, Min(1, cropTopNorm))
        cropBottomNorm = Max(0, Min(1, cropBottomNorm))

        ' Remap full-image normY -> visible-slice norm (0..1 inside the view)
        Dim adj As Float
        If cropBottomNorm > cropTopNorm Then
            adj = (normY - cropTopNorm) / (cropBottomNorm - cropTopNorm)
        Else
            adj = 0.0
        End If
        adj = Max(0, Min(1, adj))

        centerY = baseTop + adj * VH

        ' In FILL, image covers the whole view horizontally
        slider.Left = baseLeft
        slider.Width = VW
    End If

    slider.Top = Round(centerY - slider.Height / 2)
End Sub
 

Attachments

  • Screenshot_20251020_134125.jpg
    Screenshot_20251020_134125.jpg
    228.3 KB · Views: 19

walterf25

Expert
Licensed User
Longtime User
Check B4XImageView source code. You can extract it from XUI Views.b4xlib. Rename it and add it as your own custom view. This will allow you to extract everything you need.
Thanks Erel, i forgot this is a class inside the XUI lib, I've been working for 12 hours straight and running out of juice, my brain is just not braining today.

Cheers,
 
Upvote 0
Top