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
And here are the 2 functions used on the code above
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